This question was migrated from Server Fault because it can be answered on Stack Overflow.
Migrated 5 days ago.
Morning all,
I'm currently testing a PHP form on the wamp64 local server, obviously this will not be used for full deployment but just to test the functionality of the PHP form.
I have PHP 7.4.33, Windows 10, & WAMP 3.3.0
The solutions I have tried (how much time do you have?)
downloaded the latest cacert from cacert.pem, uploaded to the php7.4.33\extras\ssl\ directory & altered the curl.cainfo = "C:\wamp64\bin\php\php7.4.33\extras\ssl\cacert.pem" in my php.ini file - No dice.
followed the tutorial here https://stackoverflow.com/questions/29822686/curl-error-60-ssl-certificate-unable-to-get-local-issuer-certificate - didn't even have the options in the relevant files (apart from the php.ini file) which the OP has suggested as obviously the config files have been updated since the OP posted the post, so no dice.
I've sold my sanity to the devil - no dice, so the devils is laughing at my expense. Great!
I have used the following code below, note the SSL verify set to false - guess what? Yep, you guessed it - no dice!
looked at 60,000 poorly-explained YouTube tutorials, all of whom assume you need a 15 degrees is varying fields of astrophysics.
screamed
refered 83,000 posted on here - I think you're all getting the hand of tis "no dice" result by now.
How do I bypass the SSL verification because this is getting really silly now?
<?php
require_once 'config.php'; //this has been uploaded and in the correct directory
require 'vendor/autoload.php'; //this has been uploaded and in the correct directory
$url = "https://expired.badssl.com";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$resp = curl_exec($curl);
curl_close($curl);
var_dump($resp);
$email =new \SendGrid\Mail\Mail();
$email->setFrom("<name>#<domain>.com", "<name>");
$email->setSubject("Sending with SendGrid is a bloody disaster");
$email->addTo("<name>#<domain>.com","<name>");
$email->addTo("<name>#<domain>.com","<name>");
$email->addContent("text/plain", "and is impossible to do anywhere, even with PHP");
$email->addContent("text/plain","This is very much getting ridiculous now");
$email->addContent("text/plain", "Seriously, getting through the Volkswagen customer services is easier than getting to the bottom of this cURL error 60 issue.");
$email->addContent("text/html", "and impossible to do anywhere, even with PHP");
$sendgrid = new \SendGrid(getenv('SENDGRID_API_KEY')); //variable in 'config.json' file
try {
$response = $sendgrid->send( $email );
print $response->statusCode() . "\n";
print_r( $response->headers() );
print $response->body() . "\n";
} catch ( Exception $e ) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}
Related
In the effort to create a unified CICD process for our applications I am trying to connect to my Jenkins remote access API utilizing this (poorly documented) Jenkins-PHP API which is essentially a wrapper for the cURL functions used for accessing a remote website.
Here is my test connection:
$uname = '';
$pword = '';
$api_token = ''; // not yet used
$jenkins = new \JenkinsKhan\Jenkins("http://$uname:$pword#jenkins.svc.local/jobs");
var_dump($jenkins->isAvailable());
This returns:
bool(false)
The isAvailable() function, part of the Jenkins API class is:
public function isAvailable()
{
$curl = curl_init($this->baseUrl . '/api/json');
curl_setopt($curl, \CURLOPT_RETURNTRANSFER, 1);
curl_exec($curl);
if (curl_errno($curl)) {
return false;
} else {
try {
$this->getQueue();
} catch (RuntimeException $e) {
//en cours de lancement de jenkins, on devrait passer par là
return false;
}
}
return true;
}
EDIT: I added an echo curl_error($curl); to the conditional in the function and it returns:
Could not resolve host %mADA
NOTE: the web server I am running and the Jenkins instance are on the same network and the Jenkins instance is pingable.
I have found some unanswered question on Stack Overflow which are similar, like this one but no others which directly address the problem of connecting to the Jenkins instance.
If I change the URL string (remove the user name, replace the password with the API token, etc.) I get authentication errors at the most and a 403 (access denied) at the very least, so I feel as though I am making some headway but I am lead to believe that no real authentication occurs with the Jenkins instance.
Am I missing something obvious here? How can I make a real connection to the Jenkins remote API?
It turns out there are a couple of problems using the JenkinsKahn API class. I can only blame myself for not seeing that there had been no maintenance on the project in a year, so my current version of Jenkins wouldn't respond properly, but it did give me some hints.
Given the error was:
Could not resolve host
I started looking at the host string I was trying to access and determined that putting the user name and password in the string were making the host un-resolvable (thanks to some questions/interrogation/prodding by a good friend). Using the host string alone resulted in:
access denied (403)
First, this means I was reaching the host, but I was unable to access. Consequently I wrote some pure cURL to deal with the issue of not including the user name and password in the host string but letting cURL do the authentication.
Second, if I appended '/api/json' (according to Jenkin's docs on the subject) to the URL in my web browser I would get back a JSON string. So I made sure to include '/api/json' at the end of the URL for my cURL call.
Here is what I ended up with:
$url = "http://jenkins.svc.local/jobs/api/json";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, "$uname:$pword");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTHBASIC);
$output = curl_exec($ch);
curl_close($ch);
print_r(json_decode($output, true));
This now returns the array of information I was expecting to see and interact with. All that's left to do is use the data as needed and execute commands when required.
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'm experiencing an issue with getting the Google Analytics Managment API to work with Data Import.
When I send the data to the API via Google's PHP library, the uploaded file is visible in the "Manage Uploads" section, and appears to be correctly formatted CSV data, although the name of the file is just a random string without ".csv" at the end. See code same of this method below:
$client = new \Google_Client();
$client->setAuthConfig($config);
$client->setScopes(['https://www.googleapis.com/auth/analytics', 'https://www.googleapis.com/auth/analytics.edit']);
$analytics = new Google_Service_Analytics($client);
try {
$analytics->management_uploads->uploadData(
*****, // Account ID
*****, // Property ID
*****, // Data Set ID
[
'data' => $csvData, // contents of tmpfile, created with fputcsv, gathered with fread
'mimeType' => 'application/octet-stream',
'uploadType' => 'media',
]
);
} catch (\Exception $e) {
$response['error'] = 'Analytics Upload Error';
}
Though the data set appeared to be uploaded correctly, there was no corresponding data to be found in any reports. After downloading the file and changing the name to something ending in ".csv" and manually uploading via the web interface, the data became available. I assumed, then, that it meant that despite having the correct contents, Google wasn't handling the file correctly without the ".csv" extension.
So for my second attempt, I found references to using curl instead of their own library; doing so allowed me to pass an actual csv file, instead of just the contents of one. Example below:
$url = 'https://www.googleapis.com/upload/analytics/v3/management/accounts/' . ** Account ID ** . '/webproperties/' . ** Property ID ** . '/customDataSources/' . ** Data Set ID ** . '/uploads?access_token=' . ** Access Token **;
$file = function_exists('curl_file_create') ? curl_file_create($filename, 'application/octet-stream', 'csvData.csv') : '#' . realpath($filename);
$curl = curl_init();
$postFields = ['file_contents' => $file];
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
Again, the resulting (named) file shows up in the upload management view with a ".csv" extension and accurate data, yet it's still not visible to reporting tools. And same as the first time: downloading, renaming, and uploading via web interface works as intended, with the data being accessible in reporting.
The documentation doesn't mention any additional steps that should be taken regarding formatting, headers, etc. I'm not sure what further steps to try, since there appears to be no useful information as to what's going wrong - in fact everything looks to be working properly, yet the data is unavailable to reports when not manually uploaded.
In my PHP-based application, I've been using the Google oAuth 2 server-side flow for several years, and it has always worked flawlessly, until recently. I've been reading on any possible breaking API changes, but can't find any. Most questions having similar issues are several years old, so I'm asking a new question. It is particularly strange that this stopped working without any change on my end.
Below details are from my dev environment, but I'm getting similar results on production. This is the URL I use for getting the permission (not sure what the correct terminology is):
https://accounts.google.com/o/oauth2/auth?
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=%2Fprofile
&redirect_uri=http%3A%2F%2Fwww.jungledragon.org%2Fapps%2Fjd4%2Fsignin%2Fgoogle%2Fcallback
&response_type=code
&client_id=652476484487.apps.googleusercontent.com
&approval_prompt=auto
This seems to work correctly. If not given already, the user indeed sees the Google screen to grant access. If the user then approves proceeds, they are redirected back to my application given the callback URL.
With permission given, the next goal is to get some user data. For this, the following code is used:
// get values from the callback URL
parse_str($_SERVER['QUERY_STRING'],$_GET);
$code = $_GET['code'];
$error = $_GET['error'];
$state = $_GET['state'];
// an error reason is returned, something went wrong
if ($error_reason) { return false; }
// our app is recognized, get access token by doing a post to the Google oAuth service
$url = 'https://accounts.google.com//o/oauth2/token';
$data =
"code=" . urlencode($code) .
"&client_id=" . $this->CI->config->item('pd_oauth_google_clientid') .
"&client_secret=" . $this->CI->config->item('pd_oauth_google_clientsecret') .
"&redirect_uri=" . urlencode($this->CI->config->item('pd_oauth_google_callbackurl')) .
"&grant_type=authorization_code";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// check the result. anything but a 200 return code is an error
$info = curl_getinfo($ch,CURLINFO_HTTP_CODE);
if ($info!=200) { return false; }
As you can see, a CURL POST request is created with several parameters. None of the param values have changed and this has worked for years, yet now stopped working, for unknown reasons.
The particular problem is that the response of the post is the Google Error 404 (Not Found)!! page. This doesn't give me any meaningful info on what could be wrong.
Help is greatly appreciated, as this issue blocks all users on my production site that log in via Google authentication.
https://accounts.google.com//o/oauth2/token
will result in a 404
https://accounts.google.com/o/oauth2/token
will result in
{
"error" : "invalid_request"
}
No idea why your code worked for the last year you have an extra / in there
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