POST Request not supported by Google Server - php

I am getting following error while posting request from my server to google.com:
Warning: file_get_contents(http://accounts.google.com): failed to open stream: HTTP request failed! HTTP/1.0 405 Method Not Allowed in C:\...\index.php on line 23
My code is following:
$postdata = http_build_query(
array(
'code' => '####',
'client_id' => '####',
'client_secret' => '####',
'grant_type' => 'authorization_code'
)
);
$opts = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
$result = file_get_contents('http://accounts.google.com', false, $context);
echo $result;

the method you have chosen is 'PUT' and not 'POST'. if you want to send request as POST then change
'method' => 'PUT'
to
'method' => 'POST'

First of all what you get here is a response code (405) and it is within the error class (400 to 499 or also written as 4xx).
So the server reports back to you an error on the protocol level. The protocol used is named as well: HTTP, more specifically HTTP/1.0.
HTTP/1.0 including the status codes are outlined in RFC1945:
https://www.rfc-editor.org/rfc/rfc1945
The problem here is that the code 405 (as the concrete number) is not defined. So the docs fall back to the general description of 4xx for error codes.
HTTP/1.1 is outlined in RFC2616:
https://www.rfc-editor.org/rfc/rfc2616
It has the 405 error code details however, as the response headers in your code example show:
// ...
$result = file_get_contents('http://accounts.google.com', false, $context);
var_dump($http_response_header);
Output:
array(6) {
[0] => string(31) "HTTP/1.0 405 Method Not Allowed"
[1] => string(38) "Content-Type: text/html; charset=UTF-8"
[2] => string(19) "Content-Length: 958"
[3] => string(35) "Date: Thu, 24 Oct 2013 12:03:09 GMT"
[4] => string(15) "Server: GFE/2.0"
[5] => string(27) "Alternate-Protocol: 80:quic"
}
The required response listing shows another protocol violation as the required Allow header is not part of the response. It would have shown which methods are allowed.
So all you can do is to try if common HTTP methods work instead of PUT, you might be looking for POST. Let's run the example with POST, but no luck:
Warning: file_get_contents(http://accounts.google.com): failed to open stream: HTTP request failed! HTTP/1.0 405 HTTP method POST is not supported by this URL
I suggest you contact Google (the vendor of that online service you send HTTP requests to) and ask about the technical specification you need to match for the request you had in mind. For debugging purposes I suggest you read about PHP's special $http_response_header variable, I have some example code and explanation as well as some hints on error handling with PHP's HTTP Wrapper in:
HEAD first with PHP Streams (Sep 2011; by hakre)

Using the wrong URI, (which is why you get no allowed methods header). Access tokens are retrieved via https://accounts.google.com/o/oauth2/token "https" is required.
Unrelated: Your postdata is missing the required "redirect_uri".

This is quite late, hope it helps someone else like me.
There are two issues. First of all an access token cannot be generated with client_secret. So to have a successful request client_secret must be included.
Secondly google wants to identify the client_id, so it should also be a part of POST parameters.
The correct parameters for generating access tokens should be like
$opts = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata,
'client_id' => '######################',
'client_secret' => '##########################'
)
)

Related

Failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request - PHP Error

SOLUTION: I had malformed my JSON data for the payload body. The "ttl" => 30 was in the incorrect array() method. This probably won't help anyone in the future, moving the ttl key/value pair made this work correctly as seen below.
$data = array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),
),
"ttl" => 30
);
I have checked numerous other StackOverflow questions and cannot find a solution that works. I should note that I am testing this using a local XAMPP server running on port 8080. Not sure if that matters. I have been able to get this working using Postman, but translating it to PHP has been problematic. Am I missing something? I am not all that familiar with PHP, but need this for work.
EDIT: Some more information about what the API is expecting. It's a fairly simple API that requires a JSON body, a Basic Authorization header, and a Content-Type: application/json.
Here is the JSON body I am using in Postman. This is a direct copy/paste from Postman, which is successfully communicating with the API:
{
"statement": {
"actor": {
"mbox": "mailto:test#example.com"
}
},
"ttl": 30
}
Is there a syntax error in my below PHP code for this? Again, I am learning PHP on the fly so I'm unsure if I am properly constructing a JSON payload using the array() method in PHP.
My code below has the $https_user,$https_password, and $url domain changed for obvious security reasons. In my actual PHP code, I have the same credentials and domain used in Postman.
The $randomSessionID serves no real purpose other than an identification number for future requests. Has no affect on the API response failing or succeeding.
<?php
$https_user = 'username';
$https_password = 'password';
$randomSessionID = floor((mt_rand() / mt_getrandmax()) * 10000000);
$url = 'https://www.example.com/session/' . $randomSessionID . '/launch';
$json = json_encode(array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),"ttl" => 30
)
));
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/json\r\n'.
"Authorization: Basic ".base64_encode("$https_user:$https_password")."\r\n",
'content' => $json
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
?>
SOLUTION: I had malformed my JSON data for the payload body. The "ttl" => 30 was in the incorrect array() method. This probably won't help anyone in the future, but moving the ttl key/value pair made this work correctly as seen below.
$data = array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),
),
"ttl" => 30
);

Making POST application/json request with file_get_contents

I made a code in PHP. The code works correctly when I run the command:
$payload = file_get_contents ('request.json');
However, I need to create dynamic content for the parameters passed by request.json
I made a routine that generates a string with exactly the same content as in the request.json file. However, when I pass this content to the $payload my function does not work.
$options = array (
'http' => array (
'header' => "Content-type: application / json",
'method' => 'POST',
'content' => $reqjson,
)
);
$context = stream_context_create ($options);
$result = file_get_contents ($url, false, $context);
Why is that? Isn't the type returned by the "file_get_contents" function a common string? How to fix it?
First, each line of header must end with "\r\n". Please append that to the "Content-Type" line. Second, if the function file_get_contents() returns false, it mean the request somehow failed. You should examine $http_response_header for more information:
$options = array(
'http' => array(
'header' => "Content-type: application/json\r\n",
'method' => 'POST',
'content' => $reqjson,
),
);
$context = stream_context_create($options);
if (($result = file_get_contents($url, false, $context)) === false) {
var_dump($http_response_header);
}
If the response header ($http_response_header) starts with HTTP/1.0 400 Bad Request, it means that the server somehow think your request is malformatted. Then,
If you have access to the requested server, try to find relevant log file(s) for more information.
If you have documentations to the requested server / service, please check carefully the accepted request format.
Often request format errors can be:
"appliation/json" is not an accepted request format; or
The content of $reqjson is malformat (e.g. it is supposed to be JSON text, not PHP array).
If you're using 3rd party service and still cannot figure out why it doesn't give you the expected result, seek help from the service provider.
Thanks, Koala Yeung.
As I said, the problem is that I tried to assemble in a string exactly the same content that is inside the request.json file. However, when I use the file_get_contents function to get the contents of the json file, it works. When it is directly in the string variable, the error occurs:
array (8) {[0] => string (24) "HTTP / 1.0 400 Bad Request" [1] => string (79) "x-cloud-trace-context: db4d34cce75495db89a04731bb718b49 / 1272894976542815412; o = 0" [2 ] => string (12) "vary: origin" [3] => string (45) "content-type: application / json; charset = utf-8" [4] => string (23) "cache-control: no-cache "[5] => string (19)" content-length: 229 "[6] => string (35)" Date: Tue, 08 Dec 2020 21:01:45 GMT "[7] => string (15) "Via: 1.1 google"}
bool (false)
I believe it is something related to this type of error:
"The content of $ reqjson is malformat (e.g. it is supposed to be JSON text, not PHP array)."
But the string is identical.

HTTPS REQUEST WITH stream_context_create()

I have problem with my code, the error I get is:
Warning: fopen(https://discordapp.com/api/v6/auth/login): failed to open stream: HTTP request failed! HTTP/1.1 400 BAD REQUEST in
C:\xampp\htdocs\s2.php on line 15
Here is the relevant Code:
<?php
$data = array("email" => 'Email#gmail.com', "password" => 'Password');
$data_string = json_encode($data);
$context_options = array (
'https' => array (
'method' => 'POST',
'header'=> "Content-type: application/json\r\n"
. "Content-Length: " . strlen($data_string). "\r\n",
'content' => $data_string
)
);
$context = stream_context_create($context_options);
$fp = fopen('https://discordapp.com/api/v6/auth/login', 'r', false, $context);
?>
Thank you for your help!
It seems directly logging in via a bot is no longer allowed as you should use the OAuth2 (how does OAuth2 work?) functionality of Discord. This means that your bot needs to be set up inside your Discord account and then you may use token-based access on the bot to authenticate the external application against Discord.
The change to no longer allow bot-based logins happened around the beginning of 2017 and at that point all PHP-based Discord-related Github applications stopped to be maintained. Here is a discussion and comment about banning bots with automated login and this one about that OAuth2 has to be used.
Read more about authentication and bots in the Discord OAuth2 chapter.
If you can tell more about what you plan to achieve, maybe we can help you find a solution to your task.
Previous (no-longer working) answer:
I haven't used DiscordApp so I haven't tried this yet. Instead of sending JSON-encoded data, have you tried posting the values as FORM values to the API?
$postData = array(
'email' => 'Email#gmail.com',
'password' => 'Password'
);
$params = array('https' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postData
)
);
$context = stream_context_create($params);
// get the entire response ...
$result = file_get_contents('https://discordapp.com/api/v6/auth/login', false, $context);
// ... or alternatively using fopen()
$fp = fopen('https://discordapp.com/api/v6/auth/login', 'r', false, $context);
I haven't found any docs regarding how the parameters should be passed to the login URI but at least that's how normal form-based logins can be used.
According to the DiscordApp Response codes a 400 may be received if either the call was not understood (non-existent function called) or the parameters were send improperly so you should find out about how to call the logininterface with parameters using scripts.

PHP: 500 Server Error - Request for access token for Microsoft Azure Active Directory Access

I'm following this documentation: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
I have just completed this step (by simply visiting the URL below):
https://login.microsoftonline.com/{tenant}/oauth2/authorize?client_id={client_id}&response_type=code
Which redirected me to my redirect URL with code query string attached:
https://example.com/?code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCm.................................
At the end of the code query string above, there was an additional session_state parameter.
The next step outlined in the link at the top of this question says to make a POST request, but I'm having trouble forming this call.
Here's what the docs represent being an example:
How would I form and call this request in PHP (without using cURL)?
Here's my attempt, but I don't know whether or not I'm correct:
$url = 'https://login.microsoftonline.com/{tenant}/oath2/token';
$data = array( 'grant_type' => 'authorization_code',
'client_id' => '2d4d11a2-f814-46a7-890a-274a72a7309e',
'code' => 'AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCm...................',
'redirect_uri' => 'https://example.com',
'resource' => 'https://graph.microsoft.com',
'client_secret' => '{client_secret}' );
$options = array(
'http' => array(
'header' => 'Content-type: application/x-www-form-urlencoded',
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
$var_dump($result);
UPDATE: The code above (when executed) returns a 500 Internal Server Error.
Also, I don't know whether or not I should be adding session_state (mentioned above) into the POST call.
The URL should be https://login.microsoftonline.com/{tenant}/oauth2/token.
You have to add the client secret to the request, as well as the resource.
If you are trying to call Microsoft Graph for example, the resource should be https://graph.microsoft.com.

Why Share on LinkedIn API return 400 Bad Request?

I'm trying to post a LinkedIn share update via its Share on LinkedIn API using a PHP library LinkedIn-Client API. I've successfully authorized the user and I got the access token returned from it. I use the token along with this share API call. Here is my code:
$linkedInOAuth = new Happyr\LinkedIn\LinkedIn(LINKEDIN_APP_ID, LINKEDIN_APP_SECRET);
if ($accessToken) { // assume that it is retrieved from session
$linkedInOAuth->setAccessToken($accessToken);
$postParams = array(
"content" => array(
'description' => "I'm so exciting to share a post using API."
),
"visibility" => array(
"code" => "connnections-only"
)
);
$result = $linkedInOAuth->api(
"v1/people/~/shares",
array("format" => "json"),
"POST",
$postParams
);
}
However I got 400 bad request error returned from this API call.
Fatal error: Uncaught GuzzleException: 400: Client error response [url] https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=xxxxxxx [status code] 400 [reason phrase] Bad Request thrown in ...\vendor\happyr\linkedin-api-client\src\Happyr\LinkedIn\Http\GuzzleRequest.php on line 26
What could be the problem?
[UPDATE on 2015-04-30 3:00 PM UTC]
LinkedIn-Client API uses Guzzle internally for HTTP requests. I tried to use GuzzleHttp directly without using Happyr\LinkedIn\LinkedIn->api(), but same error and no success.
if ($accessToken) {
$url = 'https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=' . $accessToken;
$client = new GuzzleHttp\Client();
$response = $client->post($url, array(
'headers' => array(
'Content-Type' => 'application/json',
'x-li-format' => 'json'
),
'json' => array(
'comment' => 'Check out developer.linkedin.com!',
'content' => array(
'description' => 'I\'m so exciting to share a post using API.'
),
'visibility' => array(
'code' => 'connections-only'
)
)
));
}
Fatal error: Uncaught exception 'GuzzleHttp\Exception\ClientException'
with message 'Client error response [url]
https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=xxxxx
[status code] 400 [reason phrase] Bad Request' in
\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:89 Stack
trace: #0 \vendor\guzzlehttp\guzzle\src\Subscriber\HttpError.php(33):
GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Message\Request),
Object(GuzzleHttp\Message\Response)) #1
\vendor\guzzlehttp\guzzle\src\Event\Emitter.php(109):
GuzzleHttp\Subscriber\HttpError->onComplete(Object(GuzzleHttp\Event\CompleteEvent),
'complete') #2 \vendor\guzzlehttp\guzzle\src\RequestFsm.php(91):
GuzzleHttp\Event\Emitter->emit('complete', Object(Guz in
\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line
89
[UPDATE on 2015-05-05 9:40 AM UTC]
I copied and used both xml and json examples of Share on LinkedIn API page. This time, the error changed to Internal Server Error.
if ($accessToken) {
$format = 'xml';
$url = 'https://api.linkedin.com/v1/people/~/shares?format='.$format.'&oauth2_access_token=' . $connect->accessToken;
$postParams = array(
"xml" => "
<share>
<comment>Check out developer.linkedin.com!</comment>
<content>
<title>LinkedIn Developer Resources</title>
<description>Leverage LinkedIn's APIs to maximize engagement</description>
<submitted-url>https://developer.linkedin.com</submitted-url>
<submitted-image-url>https://example.com/logo.png</submitted-image-url>
</content>
<visibility>
<code>anyone</code>
</visibility>
</share>",
"json" => array(
"comment" => "Check out developer.linkedin.com!",
"content" => array(
"title" => "LinkedIn Developers Resources",
"description" => "Leverage LinkedIn's APIs to maximize engagement",
"submitted-url" => "https://developer.linkedin.com",
"submitted-image-url" => "https://example.com/logo.png"
),
"visibility" => array(
"code" => "anyone"
)
)
);
$client = new GuzzleHttp\Client();
if ($format === 'xml') {
$response = $client->post($url, array(
'body' => $postParams['xml']
));
} else {
$response = $client->post($url, array(
'headers' => array(
'Content-Type' => 'application/json',
'x-li-format' => 'json'
),
'json' => $postParams['json']
));
}
}
Fatal error: Uncaught exception 'GuzzleHttp\Exception\ServerException'
with message 'Server error response [url]
https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=xxxx
[status code] 500 [reason phrase] Internal Server Error'
According to the Github issue of Happyr\LinkedIn-API-client, some updates have been made in 0.5.0 and it solved my problem. However, LinkedIn has unclear documentation about its Share API. The following information have to be noted:
The comment field is the sharing update content. The name comment leads confusing.
Using the field comment, URL is optional in the sharing update content.
The content field means snapshot about the content of the URL you are sharing. To describe more clearly, it reflects open graph meta tags;
content.title overrides <meta property="og:title" content="..." />
content.description overrides <meta property="description" content="..." />
content.title overrides <meta property="og:title" content="..." />
content.submitted-url overrides <meta property="og:url" content="..." />
content.submitted-image-url overrides <meta property="og:image" content="..." />
When the content field is used, the field submitted-url is required. The rest are optional. If it is missing, 400 Bad Request would return.
The URLs included in the example codes of LinkedIn Share API would cause 500 Internal Server Error. They should not be used for testing purpose.
The following is the correct usage of API using Happyr\LinkedIn-API-client.
(1) Happyr\LinkedIn - Using the field comment
$linkedInOAuth = new Happyr\LinkedIn\LinkedIn(LINKEDIN_APP_ID, LINKEDIN_APP_SECRET);
// retrieve $accessToken from db or session
$linkedInOAuth->setAccessToken($accessToken);
$postParams = array(
'json' => array(
"comment" => "PHPLucidFrame - The simple, lightweight and flexible web application development framework http://phplucidframe.sithukyaw.com",
"visibility" => array(
"code" => "anyone"
)
)
);
$result = $linkedInOAuth->post('v1/people/~/shares', $postParams);
(2) Happyr\LinkedIn - Using the field content
$linkedInOAuth = new Happyr\LinkedIn\LinkedIn(LINKEDIN_APP_ID, LINKEDIN_APP_SECRET);
// retrieve $accessToken from db or session
$linkedInOAuth->setAccessToken($accessToken);
$postParams = array(
'json' => array(
"content" => array(
"title" => "PHPLucidFrame",
"description" => "The simple, lightweight and flexible web application development framework",
"submitted-url" => "http://phplucidframe.sithukyaw.com"
),
"visibility" => array(
"code" => "anyone"
)
)
);
$result = $linkedInOAuth->post('v1/people/~/shares', $postParams);
The following is the correct usage of API using GuzzleHttp.
(3) GuzzleHttp - Using the field comment
// retrieve $accessToken from db or session
$url = 'https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=' . $accessToken;
$client = new GuzzleHttp\Client();
$response = $client->post($url, array(
"json" => array(
"comment" => "PHPLucidFrame - The simple, lightweight and flexible web application development framework http://phplucidframe.sithukyaw.com",
"visibility" => array(
"code" => "anyone"
)
)
));
(4) GuzzleHttp - Using the field content
// retrieve $accessToken from db or session
$url = 'https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=' . $accessToken;
$client = new GuzzleHttp\Client();
$response = $client->post($url, array(
"json" => array(
"content" => array(
"title" => "PHPLucidFrame",
"description" => "The simple, lightweight and flexible web application development framework",
"submitted-url" => "http://phplucidframe.sithukyaw.com"
),
"visibility" => array(
"code" => "anyone"
)
)
));
The fields comment and content can also be used together.
Just a quick guess here but you might need to add json_encode to your $postParams before you send it to the API.
$result = $linkedInOAuth->api(
"v1/people/~/shares",
array("format" => "json"),
"POST",
json_encode($postParams),
);
ALTERNATIVELY
If that does not work I also notice the Linkedin Docs say the following. You could try adding these two headers (if you havent already).
By default, all API calls expect input in XML format, however if it is more covienent for your application to submit data in JSON format, you can inform the APIs that they will be receiving a JSON-formatted payload by including the following two HTTP header values in the call:
Content-Type: application/json
x-li-format: json
Your JSON post body needs to be corrected. Check:
https://developer.linkedin.com/docs/share-on-linkedin
You need to follow either one of these formats.
Share via a comment containing a URL
{
"comment": "Check out developer.linkedin.com! http://linkd.in/1FC2PyG",
"visibility": {
"code": "anyone"
}
}
Share with specific values
{
"comment": "Check out developer.linkedin.com!",
"content": {
"title": "LinkedIn Developers Resources",
"description": "Leverage LinkedIn's APIs to maximize engagement",
"submitted-url": "https://developer.linkedin.com",
"submitted-image-url": "https://example.com/logo.png"
},
"visibility": {
"code": "anyone"
}
}

Categories