Using /update-cache requests to update AMP pages - php

Trying to use /update-cache/ requests to update some AMP pages, but i'm getting 403 errors.
Removed the opening part/protocol from the urls since i don't have the reputation to post this many links, but everything is https.
I have a page at: www.qponverzum.hu/ajanlat/budapest-elozd-meg-a-hajhullast-mikrokameras-hajdiagnosztika-hajhagyma-es-fejborvizsgalattal-tanacsadas-5000-ft-helyett-2500-ft-ert-biohajklinika-szepsegapolas-egeszseg/amp
From the AMP cache: www-qponverzum-hu.cdn.ampproject.org/c/s/www.qponverzum.hu/ajanlat/budapest-elozd-meg-a-hajhullast-mikrokameras-hajdiagnosztika-hajhagyma-es-fejborvizsgalattal-tanacsadas-5000-ft-helyett-2500-ft-ert-biohajklinika-szepsegapolas-egeszseg/amp
I've been following the documentation at developers.google.com/amp/cache/update-ping
If i make an /update-ping request, it seems to work fine, returns a 200 no content response, but due to the high amount of urls/pages we would like to use /update-cache since it allows for a higher request rate.
I've created a private and public RSA key and made the public key acessible at www.qponverzum.hu/.well-known/amphtml/apikey.pub
I've been trying to use the following php code to generate the update-cache url
$ampBaseUrl = "https://www-qponverzum-hu.cdn.ampproject.org";
$signatureUrl = '/update-cache/c/s/www.qponverzum.hu/ajanlat/budapest-elozd-meg-a-hajhullast-mikrokameras-hajdiagnosztika-hajhagyma-es-fejborvizsgalattal-tanacsadas-5000-ft-helyett-2500-ft-ert-biohajklinika-szepsegapolas-egeszseg/amp?amp_action=flush&_ts='.time();
// opening the private key
$pkeyid = openssl_pkey_get_private("file://private-key.pem");
// generating the signature
openssl_sign($signatureUrl, $signature, $pkeyid)
// urlsafe base64 encoding
$signature = urlsafe_b64encode($signature);
// final url for updating
$ampUrl = $ampBaseUrl.$signatureUrl."&amp_url_signature=".$signature;
The urlsafe_b64encode function I'm using:
function urlsafe_b64encode($string) {
return str_replace(array('+','/','='),array('-','_',''), base64_encode($string));
}
$ampUrl ends up looking like this: https://www-qponverzum-hu.cdn.ampproject.org/update-cache/c/s/www.qponverzum.hu/ajanlat/budapest-elozd-meg-a-hajhullast-mikrokameras-hajdiagnosztika-hajhagyma-es-fejborvizsgalattal-tanacsadas-5000-ft-helyett-2500-ft-ert-biohajklinika-szepsegapolas-egeszseg/amp?amp_action=flush&amp_ts=1500362660&amp_url_signature=NjTCnmqUGpMY_CokGxchoczSOxnTLQvcQsX4fv2gIhW3H8hVw24mKCpmNoyV-9LND3OAR9ld80KeMH3lip863p_wBorIy1BAag7bRfvWcxsPrbqbox87VMrUWCEsry5epWxKYl2qNCT1GMv8SYAJ5WR0QZR0Qjvw5MXfZjohmbvrxJ7mWlc7fcvWoIXuO_q_yFkhi7A-fOZWm9sy8UDIlq-zNEPkVUwfqfWc_HbNHgvrk9Z6zZSNzB-dWAOT6QYAc1KeEVOIbvQxKkLkGMArTpydj5iLxz0aERvglKRl215Bqh6_jZu95T5yKv7X4R127ylpWYW2YDlTR9bgRE7Faw
If I make a simple GET request to this url(with a browser or curl) i get a 403 error('Your client does not have permission to get URL').
I've checked the webserver logs, but it doesn't seem like there're any requests made to the public keys url.
I think I'm missing something very obvious, so any feedback would be greatly appreciated.

There's an error in $signatureUrl - it should be amp_ts instead of _ts in the query params and in openssl_sign add the fourth parameter
openssl_sign($signatureUrl, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
The signature needs to be signed with SHA256, if you omit the last parameter it uses SHA1
I've used your script with these 2 changes for my work project and it's working fine.
It should return "OK" in the response body if it's fine.
Check this https://gist.github.com/krzysztofbukowski/739ccf4061d69360b5b2c8306f5878bd

Try to set the response content type to "text/plain" for https://www.qponverzum.hu/.well-known/amphtml/apikey.pub as recommended in here
=========
I use the script for update cache, but I got the 403 forbidden error.
It's hard to debug and find out the root cause.
Did someone succed?

All the other answers have really helped - thanks. I'm adding a little here which may hopefully also help.
As #kul3r4 points out (I missed it first time round) the apikey.pub file needs to be served as plain text. Here is the Nginx config rule for that;
location /.well-known/amphtml/apikey.pub { ## serve amp public key as plain/text
default_type text/plain;
}
If you are echoing out #Krzysztof Bukowski's answer to the screen, the fact that &amp is in the url parameters means my browser was stripping out the amp part of the amp_ts and amp_url_signature so be aware of that.
If you are struggling with the file paths and syntax of this;
$pkeyid = openssl_pkey_get_private("file://amp-private-key.pem");
Then just follow this answer here and put the contents of your private key in a variable -> Openssl and PHP

Related

where does this URL need urlencoding?

I hosted a website i worked on on amazon web services, and for some reason some things dont work compared to when I run it locally on localhost.
of those things are the
if (array_key_exists("error", $json))
function and
the file_get_contents function.
Ive commented out the array key exists part and that solved the issue, at least for that part of logging in, until i get to the view documents page where a slim application error displays
failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
and the issue for that lies in the viewdocspage.php file, particularly this code:
<?php
$raw = file_get_contents("http://cosoft.us-east-1.elasticbeanstalk.com/cosoft/mywiki/api.php?action=query&list=allpages&format=json");
$pages_response = json_decode($raw, true);
$pages_array = $pages_response["query"]["allpages"];
$page_titles = [];
I looked and read up on many threads that the issue lies with the file_get_contents in which the URL contains special characters, such as spaces (which mine doesnt have) and so needs to be encoded, using urlencode (or rawurlencode..?)
now ive tried encoding the whole url like this:
$raw = file_get_contents(urlencode("http://cosoft.us-east-1.elasticbeanstalk.com/cosoft/mywiki/api.php?action=query&list=allpages&format=json"));
but that resulted in this error:
slim error
Message: file_get_contents(http%3A%2F%2Fcosoft.us-east-1.elasticbeanstalk.com%2Fcosoft%2Fmywiki%2Fapi.php%3Faction%3Dquery%26list%3Dallpages%26format%3Djson): failed to open stream: No such file or directory
I figured that this may happen since I read that not all the URL should be wrapped by this encoding, but heres where Im stuck: which part of the url do i use the encoding on? the only special characters i keep coming accross regarding this error is spaces, but i dont have any spaces, so its something else which i dont know what it is...
Help is appreciated, thanks!
You would just need to url_encode the parameters. Say you had a value $value='My name is earl'
If you wanted to pass this value as a parameter in your url
http://somesite.com/?name=$value there would be spaces in the value that is url_encoded. So if you encode it as 'http://somesite.com/?name='.urlencode($value), when this is encoded the value will turn into My+name+is+earl
Reading resources from a URL may be restricted by the server's configuration.
http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen
You should use CURL for this.

Is there any option in Drive SDK for debugging?

I am having troubles with my PHP application which uses Drive SDK. I am trying to update a file, but all the time I receive 500 Internal Error message when I try to update file's contents.
I am looking for some way to debug the application. What would be most helpful for me is possibility to view how the entire request along with all headers look like. Is there any way to check it, or are there any other options for debugging?
Thank you a lot for your time.
I still didn't find any option for debugging- However, I found how I can view the requests done by the API client.
Open google-api-php-client/io/Google_REST.php file and find static public function execute(Google_HttpRequest $req) function.
There you will find this line:
$httpRequest = Google_Client::$io->makeRequest($req);
Right under it put the following code: var_dump($httpRequest);
During every request the client will do, you will get dump of it's request.
This question is still relevant but the accepted answer is very old. If you wish to view the HTTP requests and server responses in version three, the file you need to edit is /vendor/google/apiclient/src/Google/Http/REST.php. Locate the doExecute function and add print_r($request->getUri()); to the first line. Add print_r($response->getBody()->read(1024)); to the line just before the function returns to see the response body.

cURL returns half json string in most cases

First edit (more details):
I used Modify Headers plugin in Firefox and visited the page (http://api.wunderlist.com/me/tasks), this showed the full and correct json string that I need. It never fails (25+ tests)
I tried using file_get_contents, but also file_get_contents cuts the response down. At various points.
cURL does the same, cuts down the response json at various points. Looks "at random"
Original post:
I'm breaking my head on a strange issue here. I've created a PHP Wrapper for Wunderlist2 (http://www.wunderlist.com) which can be found here: https://github.com/PENDOnl/Wunderlist2-PHP-Wrapper
It worked perfectly until I was notified by a user that the class stopped working all of a sudden. Since I created a free service (http://wcal.me) to provide a calendar feed for Wunderlist users, I decided to take a look at that script since that's the most easy way for me to debug the script.
Login in to Wunderlist and fetching the authtoken works, also all other functions in the class seem to work find (getting 'me', 'me/lists', etc.) However, in case of the getTasks function ('me/tasks') the response that I get is not complete, it simply stops in the middle of a json string. Therefor the json_decode function returns NULL and thus no tasks will be available in the calender feed/method response.
I also noticed that it's pretty random, because in some cases (<10%) it works like it should, but after another refresh the output is cut in half again. Also, the exact location of the 'cut' is different per refresh.
Is there anyone that can identify what the problem is? I tried to see if there is a way to wait untill a complete download of the file before it is returned, but it would be strange if that wasn't the default behaviour of cURL. I also tried to increase the timeout time, but since it returns a value I guess it doesn't timeout either.
All code can be foundin the Github repo, so far this is the only part I've changed to debug:
// get / put / delete requests should have HTTP Code 200 OK
// only exception is the login method, which returns HTTP Code 200 OK
if($httpCode == 200 && (strtolower($method) != 'post' || $action == '/login'))
{
$return = json_decode($output, true);
if($_SERVER['REMOTE_ADDR'] == MY_IP) {
if( is_null($return) ) {
echo "<b>Output of json_decode is null:</b><br><br>";
echo $output;
} else {
echo "<b>Output of json_decode os not null:</b><br><br>";
echo $output;
}
}
return $return;
}
The full response should look like something similar to this:
[{"assignee_id":null,"completed_at":null,"completed_by_id":null,"created_at":"2013-11-10T13:16:54Z"},{"assignee_id":null,"completed_at":null,"completed_by_id":null,"created_at":"2013-11-10T13:16:54Z"}]
But instead in most cases it's:
[{"assignee_id":null,"completed_at":null,"completed_by_id":null,"created_at":"2013-11-10T13:16:54Z"},{"assignee
Of course, this is a minified response, there is more information in the response available and there are many more items in the array.
For testing purposes, if you authenticate with the class, what result does browsing to http://api.wunderlist.com/me/tasks yield?
Also I'm sure you've already fixed but in base.class.php, $action is being checked for empty values twice instead of $action & $method.
Problem was with Wunderlist, just waiting for their fix :)

Error decoding JSON input via json_decode

I'm writing my first web service, and I have a problem related to JSON data passing. I have my web service divided in two files: controller.php, which contains the service handler, and service.php, which contains the classes and methods to be served on request.
This is the acquisition fragment from controller.php:
public function atender() {
// pre-procesamos la peticiĆ³n
if (!empty($_POST)) {
if (!empty($_POST["class"]) && !empty($_POST["action"]) && !empty($_POST["function"])) {
$clase = ucwords($_POST["class"]);
$metodo = "{$_POST["action"]}{$this->obtenerMetodo($_POST["function"])}";
$id = (!empty($_POST["datos"]) ? stripslashes($_POST["datos"]) : null);
I can attend requests on both GET and POST mode (I use GET for methods not requiring authentication, like getCategories, getCategoryById, getProducts and getProductById. These are methods to get the dish categories and dishes in a sushi restaurant.)
For any of the GET requests, everything works like expected. My problem comes when I handle POST requests. I need to get all URL parameters in JSON, as this is to serve an iOS app, and JSON is the way we handle data to/from.
This is the processing fragment from service.php:
public function putUser($datos) {
if (!empty($datos)) {
$usuario = json_decode($datos);
$this->log .= implode("/", $usuario) . "\r\n";
In this case, $datos is the JSON-encoded data from the request. It's received as $id in controller.php (the code above). As it's my first web service, it's very probable I'm doing something really bad here, but I'm a bit blinded.
I've tried different variations of the service handling code. Using json_decode($datos, true) doesn't work either. I get
'Unexpected token <' as a response and, in raw form (using the advanced REST client from Google Chrome) it says: ''Warning: implode() [<a href='function.implode'>function.implode</a>]: Invalid arguments passed in /home/refine/public_html/sushigo/palma/service.php on line 344'.
I know SOAP is, usually, a better alternative to writing custom code like this but, for now, I need to stick with this code and implement a better alternative for my next project. Could you tell me what am I doing wrong?
The error message says, basically, that it is NOT a valid JSON - and such error messages are usually right.
Your error is somewhere in the sending / receiving code. Probably you send the JSON in one form and try to access it in some other way. Since I have no way of looking at the requests sent from the phone, I would guess that:
you send the data as application/json and try to receive it as an url encoded form. If you don't understand the difference, here's your problem.
you use stripslashes on the JSON data, which is wrong. UNLESS you have magic_quotes turned on, which would also be wrong (that is: both magic_quotes and stripslashes have to go).

AJAX & PHP:GET parameters causing Flickr api key error

I'm trying to send a URL with aFLickr API key to fetch results for a given photo tag. The Ajax code should return the XML to my browser. However the URL structure with parameters seems to cause a problem in my setup:
**the HTML file:**
...
url="api.flickr.com/services/rest/?method=flickr.photos.search&api_key=75564008a468bf8a284dc94bbd176dd8&tags=paris"
request.open("GET","xmlget.php?url=" + url + nocache, true)
...
**the 'xmlget.php' file:**
...
echo file_get_contents($_GET['url']);
...
error: code="100" msg="Invalid API Key (Key has invalid format)">
the link works fine if tested in the adress bar so there must be a breakdown somewhere when the URL is processed.
i tried wrapping it into encodeURI but no luck :(
Note: related post
You need to use encodeURIComponent instead of encodeURI to actually get that string encoded.
May I make 2 suggestions?
just pass the search parameters to xmlget.php and do the rest there even if it means having to pass a service type if you are using that generically
I don't remember what all a Flickr api key gets you, but it's generally a bad thing to post anything called an "api key" in public. In addition to the question, that includes sticking it in javascript that an end user can access.

Categories