I came across this problem with a friend's website. It's a Wordpress installation with several plugins. One of those plugins is used to update several images (gathering them from remote locations and storing them locally to save bandwidth). But when running the plugin, the website seemingly refused to display the updated images and continuously gave me the old version which were definetly no longer present on the server.
Browser cache was ruled out quickly as the cause. Wordpress can be a bit tricky, so I checked all other plugins, drop-ins and whether any form of object cache was active. After also ruling that out, it came to me that the hosting provider must be the issue. I didn't know and had to find out that they use Cloudflare as DNS provider to have a valid SSL certificate for their website. However by default Cloudflare also comes with caching which can be quite aggressive.
Since they liked the caching and wanted to keep it turned on, I told my friend to manually purge the cache at Cloudflare. Ta-Da - the updated images were showing just as they should.
So in order to avoid the process of logging into Cloudflare everytime the plugin is called, I was looking for a way to use their API to solve this in a convenient way. I needed some php-code (to integrate into the Wordpress-Plugin)...
I wrote a small and surely improveable php-script which serves exactly this purpose. It uses the given credentials (user-email and API key) to connect to Cloudflare's API. To retrieve the API key:
Login to the Cloudflare account.
Go to My Profile.
Scroll down to API Keys and locate Global API Key.
Click API Key to see your API identifier.
In the first step the script queries the so called Zone-ID which is a unique identifier for the domain you want to control. Since Cloudflare to date gives no option to view this ID in their backend it can only be obtained through an API request.
In the second step we again connect to Cloudflare's API, this time instructing to purge the entire cache for that Zone.
Here's my solution (I put this on the bottom of my plugin updater-script, to run after everything else has finished):
<?php
//Credentials for Cloudflare
$cust_email = ''; //user#domain.tld
$cust_xauth = ''; //retrieved from the backend after loggin in
$cust_domain = ''; //domain.tld, the domain you want to control
if($cust_email == "" || $cust_xauth == "" || $cust_domain == "") return;
//Get the Zone-ID from Cloudflare since they don't provide that in the Backend
$ch_query = curl_init();
curl_setopt($ch_query, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones?name=".$cust_domain."&status=active&page=1&per_page=5&order=status&direction=desc&match=all");
curl_setopt($ch_query, CURLOPT_RETURNTRANSFER, 1);
$qheaders = array(
'X-Auth-Email: '.$cust_email.'',
'X-Auth-Key: '.$cust_xauth.'',
'Content-Type: application/json'
);
curl_setopt($ch_query, CURLOPT_HTTPHEADER, $qheaders);
$qresult = json_decode(curl_exec($ch_query),true);
curl_close($ch_query);
$cust_zone = $qresult['result'][0]['id'];
//Purge the entire cache via API
$ch_purge = curl_init();
curl_setopt($ch_purge, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/".$cust_zone."/purge_cache");
curl_setopt($ch_purge, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch_purge, CURLOPT_RETURNTRANSFER, 1);
$headers = [
'X-Auth-Email: '.$cust_email,
'X-Auth-Key: '.$cust_xauth,
'Content-Type: application/json'
];
$data = json_encode(array("purge_everything" => true));
curl_setopt($ch_purge, CURLOPT_POST, true);
curl_setopt($ch_purge, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch_purge, CURLOPT_HTTPHEADER, $headers);
$result = json_decode(curl_exec($ch_purge),true);
curl_close($ch_purge);
//Tell the user if it worked
if($result['success']==1) echo "Cloudflare Cache successfully purged! Changes should be visible right away.<br>If not try clearing your Browser Cache by pressing \"Ctrl+F5\"";
else echo "Error purging Cloudflare Cache. Please log into Cloudflare and purge manually!";
?>
Related
I'm using Firebase to do a small project and while testing things I discovered I can do cURL requests from any server to my Firebase Database (tested on an online php tester), so I'm considering this is a security flaw for my project and I have been looking for a method to add some kind of password for cURL requests, but I found nothing, at least nothing I could understand. I know firebase have rules to manage who can read or write on my database, but I didnt find something that could filter requests by server or only allow requests that have an special password sent as parameter.
So my question is if there is a way to do something like that I could use on my project so only cURL requests made for me would work.
Here it is one of my cURL requests, in case it helps for resolving my problem.
$url = "https://mydatabase.firebaseio.com/profile/messages/".$_COOKIE['cookiename'].".json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
Thanks in advance for helping me out.
UPDATE: I found this, I think it could be the thing I need, but Im missing the part where I tell the database to ask for the access token. https://firebase.google.com/docs/database/rest/auth
One solution is to use the Firebase Auth REST API.
In particular, "you can sign in a user with an email and password by issuing an HTTP POST request to the Auth verifyPassword endpoint", see here.
Then you can use the user's uid in your Firebase security rules, in order to protect your database.
You should read and understand the documentation for the REST API. If you want to bypass security rules that would normally apply to web and mobile users, you will need to generate an OAuth token for a service account that has permissions to access your database, and use that in your requests.
If you don't want public access to your database, you will have to set up security rules to limit that. To stop all public access, your rules should be:
{
"rules": {
".read": false,
".write": false
}
}
I had hoped this was an easy task to perform, but now that I've researched it in depth for a couple of days, the whole process seems much more complicated than I had originally thought.
I would like to create a new subdomain under mydomain.com, e.g. test123.mydomain.com, using PHP via either the WHM API 1 or cPanel API 2 and subsequently a new MySQL database to be used under that new subdomain.
I'm assuming I need to authenticate with WHM first (using a WHM remote API token?), then make the call to the appropriate API module and function, and finally check the response for success or errors. Since I'm doing this with PHP, I'm assuming I would need to do this all via curl. In the cPanel API 2 docs, I see this call:
https://hostname.example.com:2087/cpsess##########/json-api/cpanel?cpanel_jsonapi_user=user&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_func=addsubdomain&domain=subdomain&rootdomain=example.com&dir=%2Fpublic_html%2Fdirectory_name&disallowdot=1
Unfortunately, that's not much help since I don't have an open "cpsess" as I'm doing this via a PHP script and replacing the "cpsess##########" with an WHM remote API token doesn't work either. I've tried a handful of different methods and so far the only one I can get to work is the cPanel API 1 example for listing accounts on the server...it works perfectly, but it's on API 1 which doesn't have the module available to create subdomains:
function getUserAccountList($user,$token){
$userList = "";
$query = "https://hostname.example.com:2087/json-api/listaccts?api.version=1";
$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);
$header[0] = "Authorization: whm $user:$token";
curl_setopt($curl,CURLOPT_HTTPHEADER,$header);
curl_setopt($curl, CURLOPT_URL, $query);
$result = curl_exec($curl);
$http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($http_status != 200) {
$userList = "[!] Error: " . $http_status . " returned\n";
} else {
$json = json_decode($result);
$userList.= "[+] Current cPanel users on the system:<BR><BR>";
foreach ($json->{'data'}->{'acct'} as $userdetails) {
$userList.= $userdetails->{'user'} . "<BR>";
}
}
curl_close($curl);
return $userList;
}
The question is: how do I create a new subdomain and MySQL database with a PHP script using either the WHM API 1 or cPanel API 2? Any help would be greatly appreciated!
I found a solution which works very well and takes most of the guesswork out of dealing with the different API versions available to cPanel and WHM:
https://www.codepunker.com/blog/using-php-to-create-new-subdomains-databases-and-email-accounts-on-a-cpanel-driven-server
This setup requires installing Composer, the PHP dependency manager, and the mgufrone/cpanel-whm package open sourced by Mochamad Gufron, so you'll need root access to the server to do so. On the link above is all of the information to get setup, as well as to both create a new subdomain and a MySQL database via the WHM/cPanel APIs with PHP.
I am using GCM services to push information from server. If I use browser key it shows the sucess mesaage as : {"multicast_id":4849013215736515938,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1348742583011905%2adac3a0f9fd7ecd"}]}
but i did not get any notifications on device.
And if I use server key it shows Unauthorized Error 401. My code is shown below:
$apiKey = "xxxxx";
$registrationIDs = array("xxxxxxxx");
$message = "testing Process";
$url = 'https://android.googleapis.com/gcm/send';
$fields = array(
'registration_ids' => $registrationIDs,
'data' => array("message"=>$message),
);
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode($fields) );
$result = curl_exec($ch);
if(curl_errno($ch)){ echo 'Curl error: ' . curl_error($ch); }
curl_close($ch);
echo $result;
Please help me for this issue. Thanks in advance.
Did you whitelist the IP of your server? This is not necessary by default for the browser key, but it is for the server key.
You can check it here:
https://code.google.com/apis/console/#project:[YOUR PROJECT NUMBER]:access
Another answer already suggested whitelisting the IP address, which seems kind of obvious. What fixed it for me was whitelisting my IPv6 address. That was the key! I hope this helps someone else.
I tried everything in this thread, and still no luck.
So I checked enabled APIs (APIs and Auth -> APIs, Enabled APIs), and realised that I had enabled Google Cloud Messaging for Chrome not Google Cloud Messaging for Android. As soon as I enabled the latter, it worked immediately.
Double check you have the right API enabled!
As many people wrote, you have to whitelist your server IPV4 and IPV6. If you want only IPV4, add this to your curl php init:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
use browser key using option create new browser key and use this key in your code.
https://code.google.com/apis/console/?pli=1#project:42053154xxxx:access
I used to put to the
$apiKey = "xxxxx"
like project number (project id) which i put to Android Client app, but i have been wrong in server have to be appkey from google cloud console, (where you activate Google Cloud Messaging for Android)
ProjectXXX -> APIs & auth -> Registered Apps -> Web App -> Server Key
-> Api key
in my case i had there default project 'Service Account-project' on platform: 'Web' but there was just Hosted Application section and no evidence about any api key.
but when i create new Web Apps called 'My app' which contained 4 sections OAuth 2.0 Client ID, Certificate, Server Key, Browser Key i finaly find the api key;-)
may just me who don't know it but i believe this answer could also helps to some one
for me the problem was that you have to enable the api. Having an API set up is not enough. Check that Google Cloud Messaging for Android appears on the enabled APIs in APIs-> enabled APIs.
If its not click the API library tab in APIS and enable it.
\
If I am not mistake your APIKEY needs to be base64 encoded.
Also try var_dump($results) to see if you get information then.
Looking at the code, I recognise this is from a php-gcm sample posted somewhere online. Its quite nice and I can assure you that both browser keys and whitelisted ip's (not IPV6 or bas64 apikey) work.
The reason why no message is shown is because the send notification function you're using 'data' => array("message"=>$message)
targets a key of "message", this is what you must pass to your pending intent i.e
notification.setLatestEventInfo(context, title, message, intent);
This will enable the intent to read the message contained under this key..the message itself is obtained from the GCMIntentService method pasted below:
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("message");
Log.d(TAG, "The intent contains: " + intent.getExtras());
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}
Here is the problem: I was using 2 servers, 1 staging and the other the production server. For my staging server, which was hosted using digital ocean, I entered the inet address in the Key for server applications allowed IP addresses, and it worked just fine.
However, it failed when I changed to my inet address from my production server. Instead, I had to use
inet6 addr: /64 Scope:Global for this to work. To get the value if you encounter the same issue, just enter ifconfig, and find the above entry. Enter that value in the allowed IP addresses and it will work fine.
You must have different project than the default one. Create a project & then create a key. Don't use default project.
Had this trouble, I was using GCM (Google cloud messaging). But after Sep 2016, the server key on the GCM will not work, you have to use FCM (firebase cloud messaging). Create new server keys only in the Firebase Console using the Cloud Messaging tab of the Settings panel. I went over to the firebase console console.firebase.google.com (I had not used it yet) and it asked me to import my project. Suddenly there was this new server key back on the GCM console. If using GCM, use the "legacy key" you see listed there.
Make sure you enabled your API Survery Key!
We are looking for solutions in days. More specifically, add this curl option: curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
I was wondering if anyone has implemented a PHP application level access to cPanel on a shared hosting provider ( in my case - Siteground). I've been looking into the documentation on the LiveAPI PHP website and it mentions that it involves managing some files in the main cPanel installation directory. I couldn't find references to any downloadable resources, so if could provide links to those and an example of how you carried out your implementation, that would be great.
I wish to programmatically (in PHP) create subdomains in cPanel and provide the respective routing directories for the same.
I found this related question but it lead to a dead end as the main PHP class link is not working
https://stackoverflow.com/questions/7549015/php-create-subdomain-over-cpanel-api
Citizen Kepler's links are now dead, and the XMLAPI at github here is deprecated.
However, combining the codes given here for authentication and here for adding a subdomain, gives us the following script which seems to work just fine on shared hosting:
<?php
$cpanelusername = "example";
$cpanelpassword = "**********";
$subdomain = 'newsubdomain';
$domain = 'example.com';
$directory = "/public_html/$subdomain"; // A valid directory path, relative to the user's home directory. Or you can use "/$subdomain" depending on how you want to structure your directory tree for all the subdomains.
$query = "https://$domain:2083/json-api/cpanel?cpanel_jsonapi_func=addsubdomain&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_version=2&domain=$subdomain&rootdomain=$domain&dir=$directory";
$curl = curl_init(); // Create Curl Object
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0); // Allow self-signed certs
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0); // Allow certs that do not match the hostname
curl_setopt($curl, CURLOPT_HEADER,0); // Do not include header in output
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1); // Return contents of transfer on curl_exec
$header[0] = "Authorization: Basic " . base64_encode($cpanelusername.":".$cpanelpassword) . "\n\r";
curl_setopt($curl, CURLOPT_HTTPHEADER, $header); // set the username and password
curl_setopt($curl, CURLOPT_URL, $query); // execute the query
$result = curl_exec($curl);
if ($result == false) {
error_log("curl_exec threw error \"" . curl_error($curl) . "\" for $query");
// log error if curl exec fails
}
curl_close($curl);
print $result;
?>
The result should be something like this:
{"cpanelresult":{"func":"addsubdomain","event":{"result":1},"apiversion":2,"module":"SubDomain","data":[{"reason":"The subdomain “newsubdomain.example.com” has been added.","result":1}],"preevent":{"result":1},"postevent":{"result":1}}}
Then to delete the subdomain run the same script, but using this query:
$deletesub = "https://$domain:2083/json-api/cpanel?cpanel_jsonapi_func=delsubdomain&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_version=2&domain=".$subdomain.'.'.$domain."&dir=$directory"; //Note: To delete the subdomain of an addon domain, separate the subdomain with an underscore (_) instead of a dot (.). For example, use the following format: subdomain_addondomain.tld
And to remove the directory (including all its contents), run this:
$deletedir = "https://$domain:2083/json-api/cpanel?cpanel_jsonapi_module=Fileman&cpanel_jsonapi_func=fileop&op=unlink&sourcefiles=$directory";
I believe that you are not looking fte the LiveAPI since the LiveAPI is for developing inside cPAnel/WHM. The LiveAPI is for creating plugins inside the cPanel and WHM interfaces.
If you are looking to add a subdomain to your account, the JSON/XML API's are much more suited to your task. If possible use the JSON api since cPanel Docs cite it as the preferred API due to it being faster than the XML api. To add a subdomain using the JSON/XML APIs you would use the following API call:
XML:
https://domain.tld:2083/xml-api/cpanel?cpanel_xmlapi_func=addsubdomain&cpanel_xmlapi_module=SubDomain&cpanel_xmlapi_version=2&domain=sub&rootdomain=maindomain.tld
JSON:
https://domain.tld:2083/json-api/cpanel?cpanel_jsonapi_func=addsubdomain&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_version=2&domain=sub&rootdomain=maindomain.tld
In the above string the arguments that you will need to modify are:
domain (string) - The local part of the subdomain you wish to add. (e.g. 'sub' if the subdomain's is sub.example.com) This value should not include the domain with which the subdomain is associated.
rootdomain (string) - The domain to which you wish to add the subdomain.
Below is further documentation including how to integrate these API commands into your php scripts and how to authorize for the API.
http://docs.cpanel.net/twiki/bin/vief/ApiDocs/Api2/ApiSubDomain#SubDomain::addsubdomain
http://docs.cpanel.net/twiki/bin/view/SoftwareDevelopmentKit/CallingAPIFunctions
http://docs.cpanel.net/twiki/bin/view/SoftwareDevelopmentKit/XmlApi
http://docs.cpanel.net/twiki/bin/view/SoftwareDevelopmentKit/ApiAuthentication
I am using GCM services to push information from server. If I use browser key it shows the sucess mesaage as : {"multicast_id":4849013215736515938,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1348742583011905%2adac3a0f9fd7ecd"}]}
but i did not get any notifications on device.
And if I use server key it shows Unauthorized Error 401. My code is shown below:
$apiKey = "xxxxx";
$registrationIDs = array("xxxxxxxx");
$message = "testing Process";
$url = 'https://android.googleapis.com/gcm/send';
$fields = array(
'registration_ids' => $registrationIDs,
'data' => array("message"=>$message),
);
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode($fields) );
$result = curl_exec($ch);
if(curl_errno($ch)){ echo 'Curl error: ' . curl_error($ch); }
curl_close($ch);
echo $result;
Please help me for this issue. Thanks in advance.
Did you whitelist the IP of your server? This is not necessary by default for the browser key, but it is for the server key.
You can check it here:
https://code.google.com/apis/console/#project:[YOUR PROJECT NUMBER]:access
Another answer already suggested whitelisting the IP address, which seems kind of obvious. What fixed it for me was whitelisting my IPv6 address. That was the key! I hope this helps someone else.
I tried everything in this thread, and still no luck.
So I checked enabled APIs (APIs and Auth -> APIs, Enabled APIs), and realised that I had enabled Google Cloud Messaging for Chrome not Google Cloud Messaging for Android. As soon as I enabled the latter, it worked immediately.
Double check you have the right API enabled!
As many people wrote, you have to whitelist your server IPV4 and IPV6. If you want only IPV4, add this to your curl php init:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
use browser key using option create new browser key and use this key in your code.
https://code.google.com/apis/console/?pli=1#project:42053154xxxx:access
I used to put to the
$apiKey = "xxxxx"
like project number (project id) which i put to Android Client app, but i have been wrong in server have to be appkey from google cloud console, (where you activate Google Cloud Messaging for Android)
ProjectXXX -> APIs & auth -> Registered Apps -> Web App -> Server Key
-> Api key
in my case i had there default project 'Service Account-project' on platform: 'Web' but there was just Hosted Application section and no evidence about any api key.
but when i create new Web Apps called 'My app' which contained 4 sections OAuth 2.0 Client ID, Certificate, Server Key, Browser Key i finaly find the api key;-)
may just me who don't know it but i believe this answer could also helps to some one
for me the problem was that you have to enable the api. Having an API set up is not enough. Check that Google Cloud Messaging for Android appears on the enabled APIs in APIs-> enabled APIs.
If its not click the API library tab in APIS and enable it.
\
If I am not mistake your APIKEY needs to be base64 encoded.
Also try var_dump($results) to see if you get information then.
Looking at the code, I recognise this is from a php-gcm sample posted somewhere online. Its quite nice and I can assure you that both browser keys and whitelisted ip's (not IPV6 or bas64 apikey) work.
The reason why no message is shown is because the send notification function you're using 'data' => array("message"=>$message)
targets a key of "message", this is what you must pass to your pending intent i.e
notification.setLatestEventInfo(context, title, message, intent);
This will enable the intent to read the message contained under this key..the message itself is obtained from the GCMIntentService method pasted below:
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("message");
Log.d(TAG, "The intent contains: " + intent.getExtras());
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}
Here is the problem: I was using 2 servers, 1 staging and the other the production server. For my staging server, which was hosted using digital ocean, I entered the inet address in the Key for server applications allowed IP addresses, and it worked just fine.
However, it failed when I changed to my inet address from my production server. Instead, I had to use
inet6 addr: /64 Scope:Global for this to work. To get the value if you encounter the same issue, just enter ifconfig, and find the above entry. Enter that value in the allowed IP addresses and it will work fine.
You must have different project than the default one. Create a project & then create a key. Don't use default project.
Had this trouble, I was using GCM (Google cloud messaging). But after Sep 2016, the server key on the GCM will not work, you have to use FCM (firebase cloud messaging). Create new server keys only in the Firebase Console using the Cloud Messaging tab of the Settings panel. I went over to the firebase console console.firebase.google.com (I had not used it yet) and it asked me to import my project. Suddenly there was this new server key back on the GCM console. If using GCM, use the "legacy key" you see listed there.
Make sure you enabled your API Survery Key!
We are looking for solutions in days. More specifically, add this curl option: curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );