I'm working with a wordpress plugin called Instagrabber: pluggin page. The plugin had been working perfectly for several months up until about a week ago when it started failing authentication while updating the image stream. At first, I thought the token expired, but after creating a few new testing accounts, the problem persisted.
I've isolated the problem to a couple lines of code in the main instagrabber-api.class.php file, pertaining to authenticating and retrieving the content:
$response = wp_remote_post( $request_uri, array(
'timeout'=> 10,
'method' => 'POST',
'body' => $data
)
);
$decoded_response = json_decode($response['body']);
This throws an 500 internal server error, and authentication fails. I've successfully authenticated using instagram's localhost setting, and connected with their API console, but when I make the request from our host, it fails.
This may not cover everything, so I'm happy to provide additional information, if needed.
** Edited **
Here are the values for $data and $response:
$data = Array (
'client_id' => $InstagramClientID,
'client_secret' => InstagramClientSecret,
'grant_type' => 'authorization_code',
'redirect_uri' => $InstagramRedirectURI,
'code' => $auth_code
)
If I print $data, everything appears fine, with all values pulling correctly.
$response is an array using wp_remote_post default return values, which can be found here for reference. The following is what we get returned:
Array (
[headers] =>
Array (
[cache-control] => no-cache
[content-type] => text/html
[date] => Mon, 07 Apr 2014 13:15:33 GMT
[server] => nginx
[content-length] => 87
[connection] => Close )
[body] =>
This seems to be where the 500 server error stems from. My thought is because of the Connection = Close, and empty body content.
Related
According to Vimeo API documentation:
The If-Modified-Since header enables you to return only those API resources that have been modified since a particular date and time.
The header looks like this:
If-Modified-Since: {ddd}, {D} {MMM} {YYYY} {HH}:{mm}:{ss} {Z}
NOTE: If your formatting codes are rusty, Tue, 20 Jun 2023 14:42:36 GMT is an example.
If none of the resources have been modified since this date, the API returns an empty response body and the HTTP status 304 Not Modified.
I'm using the Official PHP library for the Vimeo API.
According to GitHub issue #130, the PHP library's request() method accepts an array of headers. And this commit shows how the $headers array is passed and parsed:
public function request($url, $params = array(), $method = 'GET',
$json_body = true, array $headers = array())
// Set the headers
foreach ($headers as $key => $value) {
$curl_opts[CURLOPT_HTTPHEADER][] = sprintf('%s: %s', $key, $value);
}
But when I pass the future date shown in the example, I still receive a full list of videos rather than the "empty response body and the HTTP status 304 Not Modified" specified in the documentation.
What am I doing wrong?
$fields = array(
'created_time',
'modified_time'
);
$params = array(
'page' => $page,
'filter' => 'embeddable',
'filter_embeddable' => true,
'fields' => implode(',',$fields)
);
$headers = array(
'If-Modified-Since' => 'Tue, 20 Jun 2023 14:42:36 GMT'
);
$json_body = true;
$method = 'GET';
$response = $vimeo->request('/me/videos', $params, $method, $json_body, $headers);
Result:
Array
(
[0] => Array
(
[created_time] => 2018-06-05T19:27:18+00:00
[modified_time] => 2018-06-29T19:12:21+00:00
)
[1] => Array
(
[created_time] => 2016-06-02T03:01:40+00:00
[modified_time] => 2019-04-30T06:15:29+00:00
)
[2] => Array
(
[created_time] => 2016-05-29T05:31:46+00:00
[modified_time] => 2019-04-25T07:46:53+00:00
)
....
Edit
Based on this answer (not about Vimeo), it seems that the API might return the entire set of videos if even one of them was modified after the "If-Modified-Since" date.
If anything has changed in the entire response, then it will send the entire response to you.
But I'd still expect the result to be empty if the date is in the future. Am I misunderstanding?
Edit
Tom suggested that the Vimeo API ignores "If-Modified-Since" headers that are set in the future. I tried setting mine in the recent past, but I'm still getting results that were modified before that date:
$vimeo = new \Vimeo\Vimeo(false,false,$access_token);
$fields = array(
'modified_time'
);
$params = array(
'page' => 1,
'fields' => implode(',',$fields)
);
$method = 'GET';
$json_body = true;
$headers = array(
'If-Modified-Since' => 'Fri, 24 May 2019 14:42:36 GMT'
);
$response = $vimeo->request('/me/videos', $params, $method, $json_body, $headers);
echo"<pre>".print_r($response,true)."</pre>";
The result includes:
[21] => Array
(
[modified_time] => 2019-05-16T17:22:58+00:00
)
[22] => Array
(
[modified_time] => 2019-05-12T08:07:30+00:00
)
Edit
I was wrong. As mentioned above, I believe the entire response is returned if any item in the response has been modified since the "If-Modified-Since" timestamp. That made it look like the header wasn't working. But I set the timestamp as close as possible to the current time and I did get a "304 Not Modified" response, as Tom reported in his answer below. Others (content producers) also have access to the Vimeo account I'm testing against and I wasn't aware how recently they had modified content.
It's not documented by Vimeo, but I found out by experiment that:
When If-Modified-Since lies in the future, it is ignored.
Otherwise, the header works as expected. But take care of your timezones and possible clock-skew of a few seconds.
Vimeo's modification time is shown in the API response, in my case:
"modified_time": "2019-05-22T09:52:45+00:00",
If-Modified-Since: Wed, 22 May 2019 09:56:25 GMT returns a 304 Not Modified for my situation.
I've submitted a support request to Vimeo to clarify or change this behaviour.
I am using official Vimeo PHP client.
I can upload a video, and set privacy.embed to whitelist.
Then doc tells me:
To add a domain to the whitelist, send a PUT request to /videos/{video_id}/privacy/domains/{domain}.
I tried
$privacy_uri = $uri . "/privacy/domains/testdomain.tld";
$domain_add_response = $client->request($privacy_uri);
where
- $uri is the /vimeo/<video_id>
- $client is born from new Vimeo(CLIENT_ID, CLIENT_SECRET, VIMEO_TOKEN);
Problem
Printing the $domain_add_response I get a 405 error, probably because of Allow (see the following response dump)
Array
(
[body] =>
[status] => 405
[headers] => Array
(
[Server] => nginx
[Content-Type] => application/json
[Allow] => PUT,DELETE,OPTIONS
[X-Vimeo-DC] => ge
[Accept-Ranges] => bytes
[Via] => 1.1 varnish
[Content-Length] => 0
[Date] => Mon, 15 Apr 2019 08:30:47 GMT
[Connection] => keep-alive
[X-Served-By] => cache-bwi5125-BWI, cache-mxp19820-MXP
[X-Cache] => MISS, MISS
[X-Cache-Hits] => 0, 0
[X-Timer] => S1555317047.232635,VS0,VE148
[Vary] => Accept-Encoding
)
)
I imagine I must set the PUT method in my request, but ... how ?
Solution found looking at api source code: https://github.com/vimeo/vimeo.php/blob/master/src/Vimeo/Vimeo.php#L88
where the signature of request is
public function request($url, $params = array(), $method = 'GET', $json_body = true, array $headers = array()): array
I understand that I can fix the problem, simply passing an empty $params array and specifing PUT as request $method
I changed this line
$domain_add_response = $client->request($privacy_uri);
Into this form
$domain_add_response = $client->request($privacy_uri, [], 'PUT');
And it works as expected
I'm attempting to authenticate a user through Vimeo in order to view a list of their videos on the website.
I'm using the Vimeo php library https://github.com/vimeo/vimeo.php with no errors when including it in my code.
I get the authentication URL and am able to navigate to the Allow APP Access page on Vimeo and when I click "Allow" I'm getting the "invalid_client" error on my redirect page, even though they send back a code in the $_GET.
I'm thoroughly confused at this point since I've got the official API library and the APP is set up correctly as far as I can tell. I'm hoping someone might be able to point me in the right direction as to why I'm getting this error and how to fix it!
My Code:
//init Vimeo
require_once("modules/classes/Vimeo/autoload.php");
$lib = new \Vimeo\Vimeo($vimeo_id, $vimeo_secret, $vimeo_access);
if(!isset($_SESSION['vstate'])){
$_SESSION['vstate'] = base64_encode(openssl_random_pseudo_bytes(30));
}
$vimeo_authurl = $lib->buildAuthorizationEndpoint($redirecturi,'public private',$_SESSION['vstate']);
if(isset($_GET['code'])){
echo "Code returned: ".$_GET['code'];
if ($_SESSION['vstate'] != $_GET['state']) {
echo 'Something is wrong. Vimeo sent back a different state than this script was expecting. Please let an administrator know that this has happened.';
}
$tokens = $lib->accessToken($_GET['code'], $redirecturi);
if ($tokens['status'] == 200) {
echo 'Vimeo account successfully connected!';
$_SESSION['access_token'] = $tokens['body']['access_token'];
$lib->setToken($token['body']['access_token']);
} else {
echo 'Sorry, we were unable to connect to your Vimeo account due to the following error:<br/>{'.$tokens['body']['error']."} ".$tokens['body']['error_description'];
}
echo "<br/><br/><pre>";
print_r($tokens);
echo "</pre>";
exit();
}
The print_r($tokens) gives this:
Array
(
[body] => Array
(
[error] => invalid_client
[error_description] => A valid client ID must be provided along with any request made to Vimeo's API
)
[status] => 400
[headers] => Array
(
[Server] => nginx
[Content-Type] => application/json
[Expires] => Fri, 10 Mar 2017 03:11:17 GMT
[Cache-Control] => no-store
[Strict-Transport-Security] => max-age=15552000; includeSubDomains; preload
[Pragma] => no-cache
[X-UA-Compatible] => IE=edge
[X-XSS-Protection] => 1; mode=block
[X-Content-Type-Options] => nosniff
[X-Frame-Options] => sameorigin
[Content-Security-Policy-Report-Only] => default-src https: data: blob: 'unsafe-inline' 'unsafe-eval'; report-uri /_csp
[Accept-Ranges] => bytes
[Via] => 1.1 varnish
[Fastly-Debug-Digest] => 5da2a3ac863afd5f2ad0963779e0dbc4c54c7d97d19f87fd227c5eb8c92bd621
[Content-Length] => 126
[Date] => Fri, 10 Mar 2017 15:11:17 GMT
[Connection] => keep-alive
[X-Served-By] => cache-iad2146-IAD, cache-ord1731-ORD
[X-Cache] => MISS, MISS
[X-Cache-Hits] => 0, 0
[X-Timer] => S1489158677.346607,VS0,VE55
[Vary] => Accept,Vimeo-Client-Id,Accept-Encoding,User-Agent
)
)
So I'm not exactly sure why, but I created a new APP with the same details and this new APP seemed to authenticate fine.
The first APP I was having troubles with I had originally sent a request for Upload Access, but was denied (due to local testing links), so perhaps that was the underlying issue with the "invalid_client" error.
I am trying to implement OAuth2 with Doctrine as an entity manager. I followed this tutorial exactly:
http://bshaffer.github.io/oauth2-server-php-docs/cookbook/doctrine2/
Here is my code that is called when a user makes a request to the API:
// obtaining the entity manager
$entityManager = EntityManager::create($conn, $config);
$clientStorage = $entityManager->getRepository('OAuthClient');
$clients = $clientStorage->findAll();
print_r($clients); // We are getting the clients from the database.
$userStorage = $entityManager->getRepository('OAuthUser');
$accessTokenStorage = $entityManager->getRepository('OAuthAccessToken');
$authorizationCodeStorage = $entityManager->getRepository('OAuthAuthorizationCode');
$refreshTokenStorage = $entityManager->getRepository('OAuthRefreshToken');
//Pass the doctrine storage objects to the OAuth2 server class
$server = new \OAuth2\Server([
'client_credentials' => $clientStorage,
'user_credentials' => $userStorage,
'access_token' => $accessTokenStorage,
'authorization_code' => $authorizationCodeStorage,
'refresh_token' => $refreshTokenStorage,
], [
'auth_code_lifetime' => 30,
'refresh_token_lifetime' => 30,
]);
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($clientStorage));
// handle the request
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
Whenever a call using the correct credentials is made, I get this response:
Array
(
[0] => OAuthClient Object
(
[id:OAuthClient:private] => 1
[client_identifier:OAuthClient:private] => testclient
[client_secret:OAuthClient:private] => testpass
[redirect_uri:OAuthClient:private] => http://fake.com
[hashOptions:protected] => Array
(
[cost] => 11
)
)
[1] => OAuthClient Object
(
[id:OAuthClient:private] => 2
[client_identifier:OAuthClient:private] => trevor
[client_secret:OAuthClient:private] => hutto
[redirect_uri:OAuthClient:private] => https://www.another.com
[hashOptions:protected] => Array
(
[cost] => 11
)
)
)
{"error":"invalid_client","error_description":"The client credentials are invalid"}
So we are getting the clients from the database, we should be checking them, and returning that they in fact exists and issuing an access token. However, for some reason, OAuth2 Server (can be seen here) can not match the given credentials with the stored credentials.
I do not think this is a Doctrine problem because I can retrieve the results fairly easily using findAll().
My question is:
Why is this happening, and how can I fix it?
I found the problem. In the tutorial (http://bshaffer.github.io/oauth2-server-php-docs/cookbook/doctrine2/) they fail to mention that when the client secret is checked with against a hashed version of the provided client secret.
In the tutorial they do not hash the example client secret when they put it in the database.
If you hash your client secret when inserting it into the database, it will work as expected.
I'm trying to run a simple Web app over a ReactPHP Web server, but I can't figure out where to get POST data coming from an HTML form. The server is defined as:
include 'vendor/autoload.php';
register_shutdown_function(function() {
echo implode(PHP_EOL, error_get_last()), PHP_EOL;
});
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket);
$http->on('request', function(React\Http\Request $request, React\Http\Response $response) {
print_r($request);
$response->writeHead(200, array('Content-type' => 'text/html'));
$response->end('<form method="POST"><input type="text" name="text"><input type="submit" name="submit" value="Submit"></form>');
});
$socket->listen(9000);
$loop->run();
When I post some string using the HTML form, the $request object, when printed on the console, looks like:
React\Http\Request Object
(
[readable:React\Http\Request:private] => 1
[method:React\Http\Request:private] => POST
[path:React\Http\Request:private] => /
[query:React\Http\Request:private] => Array
(
)
[httpVersion:React\Http\Request:private] => 1.1
[headers:React\Http\Request:private] => Array
(
[User-Agent] => Opera/9.80 (X11; Linux i686) Presto/2.12.388 Version/12.16
[Host] => localhost:9000
[Accept] => text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
[Accept-Language] => it,en;q=0.9
[Accept-Encoding] => gzip, deflate
[Referer] => http://localhost:9000/
[Connection] => Keep-Alive
[Content-Length] => 24
[Content-Type] => application/x-www-form-urlencoded
)
[listeners:protected] => Array
(
)
)
Here I can't find my data anywhere. I thought it should be located in the query property, but it's empty.
When I make GET requests, instead, data passed in the querystring can be found inside the query property of the $request object.
So, where can I find data passed with POST requests?
I repeat the last edit to my question here, so this question can be marked as answered.
Nevermind, found an answer here. Basically, it seems that React PHP does not support an easy way to read POST data yet. What we can do, though, is to read data as soon as it comes, watching the event data of the $request object:
$request->on('data', function($data) {
// Here $data contains our POST data.
// The $request needs to be manually ended, though.
});