Upload file to Bitbucket via PHP script - php

I try to upload my database to bitbucket downloads section of my repository via a PHP script using curl library. Normally i go to my phpmyadmin and export my database to a folder, then going to my bitbucket account under downloads section of my repository and upload manually. I need a script that automates these tasks.
I tried using curl library like this:
// bitbucket username and password
define('USERNAME', 'my_username');
define('PASSWORD', 'my_password');
$url = 'https://bbuseruploads.s3.amazonaws.com/';
//This needs to be the full path to the file you want to send.
$file_name_with_full_path = realpath('apache_pb2.gif');
$post = array('extra_info' => '123456', 'file_contents' => '#' . $file_name_with_full_path); // image file example here
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, USERNAME . ":" . PASSWORD);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$resp = curl_exec($ch);
// validate CURL status
if (curl_errno($ch))
throw new Exception(curl_error($ch), 500);
The result:
<error><code>InvalidArgument</code>
<message>Unsupported Authorization Type</message>
<argumentvalue>Basic hash_code_here</argumentvalue>
<argumentname>Authorization</argumentname>
<requestid>hash_code_here</requestid>
<hostid>hash_code_here</hostid>
</error>
If you need further clarifications please let me know.

Just for the case someone finds this old corpse here:
I solved it by this funktion function:
/**
* Uploads a file to Bitbucket Download area of the configured repository
* Does the same as thi bash command:
* curl -X POST "https://USER:PW#api.bitbucket.org/2.0/repositories/owner/slug/downloads/" --form files=#"test.txt"
* #param string $filename
* #param string $apiEndpoint
* #param string $apiUser
* #param string $apiPassword
* #return bool|string
* #throws Deployer\Exception\Exception
*/
public static function sendFileToDownload(
string $filename,
string $apiEndpoint,
string $apiUser,
string $apiPassword
) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $apiEndpoint);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLAUTH_BASIC, 1);
curl_setopt($curl, CURLOPT_USERPWD, "$apiUser:$apiPassword");
$data = [
'files' => curl_file_create($filename),
];
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$erg = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($erg === false || $status > 300) {
throw new Deployer\Exception\Exception("Result: ".print_r($erg, true), $status);
}
curl_close($curl);
}
}
For me the most important point was this section:
$data = [
'files' => curl_file_create($filename),
];
This results in a local file been uploaded to my repos download area with the name $filename (filename path).

Had this same problem today. "Unsupported Authorization Type" response from an API CURL request.
I spent a long time consulting with Google. In the end, I discovered that my URL had two slashes in it together (accidentally). See, the API I'm connecting to has a URL, and then an API endpoint. Like this:
https://www.example.com/api/v2/foo -or-
https://www.example.com/api/v2/bar
But I accidentally was combining them like this:
curl_setopt($curl, CURLOPT_URL, $url ."/". $endpoint);
given my data:
$url = "https://www.example.com/api/v2/"
$endpoint = "foo"
I ended up with this:
"https://www.example.com/api/v2//foo"
Problem solved by removing the ."/". and just making it this: .
BONUS POSSIBILITY: Something else interesting I learned in the process was that the API folks prefer double-quotes around json data posted to them. I haven't verified it makes a difference, but instead of wrapping double-quotes in single-quotes (or visa-versa), escaping the internal double-quotes is how I left things. And it's working.

Related

how to create curl commands on moodle

I'm recently started developing on moodle and one big problem is that whenever i build a plugin with a web page, it don't execute any of my curl commands, i hear that moodle has his own php library(an php file called filelib.php i suppose) with curl commands and i should be using its commands instead of mine, but i don't have much experience with moodle development and php so all that code make me very confused.
i tried this question before and a gentleman helped me with an example, i tried his code and it didn't work(it changed the output but still show an error message, i also tried changing the code to no avail) and i didn't get much of an explanation about how curl commands work on moodle(i'm still grateful for his help) or whats commands on filelib.php will substitue my code, can someone help me?
my code:
<?php
require_once(__DIR__.'/../../config.php');
require_once($CFG->libdir.'/filelib.php');
$PAGE->set_url(new moodle_url(url:'/local/iesde/selecionaraulas.php'));
$PAGE->set_context(\context_system::instance());
$PAGE->set_title('selecionar aulas');
$PAGE->requires->js_call_amd('local_iesde/tabelas', 'init');
echo $OUTPUT->header();
echo $OUTPUT->render_from_template('local_iesde/manageaulas', $templatecontext);
$api_server = 'url';
$api_http_user = 'user';
$api_http_pass = 'pass';
$key_acess = 'key';
$key_name = 'API-KEY';
$format = 'json';
$params = array(
'IDstudent' => 000000,
'IDcourse' => 000000,
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "{$api_server}/format/{$format}");
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_setopt($curl, CURLOPT_USERPWD, "{$api_http_user}:{$api_http_pass}");
curl_setopt($curl, CURLOPT_HTTPHEADER, array("{$key_name}:{$key_acess}"));
curl_setopt($curl, CURLOPT_NOBODY, 1);
curl_exec($curl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
$output = curl_exec($curl);
var_dump(json_decode($output));
echo $output;
echo $OUTPUT->footer()
the purpose of this curl request is to print a list of ids that will be used on another curl request to generate a video file that will be executed on a videoplayer, the variables:
$api_server = 'url';
$api_http_user = 'user';
$api_http_pass = 'pass';
$key_acess = 'key';
$key_name = 'API-KEY';
$format = 'json';
$params = array(
'IDstudent' => 000000,
'IDcourse' => 000000,
);
Are all needed to execute the commands (one of the reasons i think the gentleman's example didn't work is that it didn't used all the variables of the code to get full validation).
well that is all, i'm very new to all of this so any explanation will help, thanks for the help.

PHP CURL request with PEM certificate unstable results

I'm trying to get results from a server which is protected with an PEM cerficate and private key.
I have results, but it is unstable. Most of te time i have response, sometimes an Curl error: NSS: private key from file not found.
The code:
$url = escape($this->url).'/jira/rest/api/2/project';
// Variables
$apiGrantType = 'client_credentials';
$cliendId = $this->username; // Client ID
$clientSecret = $this->password; // Client Secret
$certUserPwd = $cliendId . ":" . $clientSecret; // Client ID:Client Secret
$certFile = PATH_FILES.'certificate/cert.pem'; // Private Cert
$certKey = PATH_FILES.'certificate/key.pem'; // Private Cert
$certPassword = '*****'; // Cert Password
$curl = curl_init();
curl_setopt($curl, CURLOPT_USERPWD, PWSTR);
curl_setopt($curl, CURLOPT_URL, $url);
//curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_SSLCERT, $certFile);
curl_setopt($curl, CURLOPT_SSLKEY, $certKey);
curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $certKey);
//curl_setopt($curl, CURLOPT_TIMEOUT, 30);
//curl_setopt($curl, CURLOPT_VERBOSE, 1);
if(!$exec = curl_exec($curl))
{
echo 'Curl error: ' . curl_error($curl);
}
dump($exec);
Sometimes it runs perfectly and returns the requested response.
Othertimes it return Curl error: NSS: private key from file not found.
Server where request is calling from is running on CENTOS 7 and PHP 7.2.
How can i make my request stable?
I know this is an old thread, but recently had same issue.
Based on the above code, it looks like the curl definitions are within a class, and that one is used with include/include_once or require/require_once.
In my case seems that using include_once/require_once was the reason, hence
you can replace any include_once/require_once in favour of include/require.
alternatively use something like
if (!class_exists('some_class')) {
include 'some_path/some_class.php';
}

How do I make a simple PHP API handler?

I've written a basic API script in PHP using cURL - and successfully used a version of it on another API, this one is specifically to handle domain DNS management on DigitalOcean - and I can't send data?
Prelude...
I understand there is a PHP library available, I'm not after something that full featured or bloated with dependencies - just something small to use locally and primarily to help me understand how RESTful API's work a little better in practice - an educational exercise
The offending Code...
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
var_dump(basic_api_handle($api_key, 'POST', 'https://api.digitalocean.com/v2/domains', array('name' => 'my-domain.tld', 'ip_address' => '1.2.3.4')));
This works with a GET request, such as listing the domains on the account but seems to fail at posting/sending data... this results in "unprocessable_entity" and "Name can't be blank" - as the name is not blank and is correctly formatted (as far as I can tell) it suggests to me the data is not being sent correctly?
Solution Attempts so far...
I've tried json encoding the data (seen in code), not json encoding, url encoding with and without json encoding and various other options with no luck.
I've seen a few posts online about this exact same issue specifically with DigitalOcean's API (and a another) but no one had an explanation (other than give up and use the library or something to that affect).
Using cURL directly from a terminal does work etc so there is nothing wrong with the API for creating a domain.
As far as I understand, the authentication is working, and the general setup works as I can list domains within the account, I just cant POST or PUT new data. I've been though the API's documentation and can't see what I'm doing wrong, maybe some sort of wrong encoding?
Any help would be much appreciated! :)
Edit:
After much work and research even other simple API handlers do not work with Digital Ocean (such as https://github.com/ledfusion/php-rest-curl) - is there something this API in particular needs or am I missing something fundamental about API's in general?
Technically this is not an fix but a work around. Thank you everyone for your comments and ideas, unfortunately nothing worked/fixed the code and the bounty expired :(
Although I have no idea why the PHP cURL option didn't work (the HTTP works, just Digital Ocean spitting errors for unknown reason linked to validation of the post data)...
I do have a new method that DOES WORK finally... (thanks to jtittle post on the Digital Ocean Community forum)
Just incase that link dies in the future... he's the working function using streams and file_get_contents and not curl...
<?php
function doapi( $key, $method, $uri, array $data = [] )
{
/**
* DigitalOcean API URI
*/
$api = 'https://api.digitalocean.com/v2';
/**
* Merge DigitalOcean API URI and Endpoint URI
*
* i.e if $uri is set to 'domains', then $api ends up as
* $api = 'https://api.digitalocean.com/v2/domains'
*/
$uri = $api . DIRECTORY_SEPARATOR . $uri;
/**
* Define Authorization and Content-Type Header.
*/
$headers = "Authorization: Bearer $key \r\n" .
"Content-Type: application/json";
/**
* If $data array is not empty, assume we're passing data, so we'll encode
* it and pass it to 'content'. If $data is empty, assume we're not passing
* data, so we won't sent 'content'.
*/
if ( ! empty( $data ) )
{
$data = [
'http' => [
'method' => strtoupper( $method ),
'header' => $headers,
'content' => json_encode( $data )
]
];
}
else
{
$data = [
'http' => [
'method' => strtoupper( $method ),
'header' => $headers
]
];
}
/**
* Create Stream Context
* http://php.net/manual/en/function.stream-context-create.php
*/
$context = stream_context_create( $data );
/**
* Send Request and Store to $response.
*/
$response = file_get_contents( $uri, false, $context );
/**
* Return as decoded JSON (i.e. an array)
*/
return json_decode( $response, true );
}
/**
* Example Usage
*/
var_dump(doapi(
'do-api-key',
'get',
'domains'
));
I used this to actually post the data successfully...
var_dump(doapi(
$api_key,
'post',
'domains',
array("name" => (string) $newDomain, "ip_address" => "1.2.3.4")
));
Add the Content-Length header and use CURLOPT_POST option for POST requests
function basic_api_handle($key, $method, $URI, $data) {
$json = json_encode($data)
$headers = array(
'Authorization: Bearer '.$key,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $URI);
if ( $method === 'POST' ) {
curl_setopt($curl, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
array_push($headers, 'Content-Length: ' . strlen($json) );
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers)
curl_setopt($ch, CURLOPT_POSTFIELDS, $json );
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
Maybe this will work for you:
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); // <-- Should be set to "GET" or "POST"
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // <-- Maybe the SSL is the problem
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"); // <-- I am not familiar with this API, but maybe it needs a user agent?
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POST, count($data)); // <-- Add this line which counts the inputs you send
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
It can also be a problem of a header you should sent and your missing it.
It could be a 307 or 308 http redirect.
Maybe "https://api.digitalocean.com/v2/domains" redirects to another url.
If this is the case, try adding:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
to make curl follow the redirection and keep the parameters.
It is suggested that you also use:
curl_setopt($curl, CURLOPT_POSTREDIR, 3);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
to keep the request body.
Hope it helps.
You can also try use CURLOPT_POST

Working with ChannelAdvisor REST API in PHP - requests not working in CURL

I would like to integrate with ChannelAdvisor REST API using the SOAP Credentials Flow.
Based on their documentation, I have setup the following in PostMan (rest client in Chrome browser) like this:
When I make the rest; the rest api server returns the expected response:
So, I tried to replicate this in PHP with the following class:
<?php
class ChannelAdvisorREST {
/**
* ChannelAdvisor constants & properties
*/
const BASE_URL = 'https://api.channeladvisor.com/v1';
private $config;
/**
* Class constructor
*/
public function __construct()
{
$this->config = \Config::get('channeladvisor');
}
// TEST
public function test($accountId)
{
// var_dump($this->config);
var_dump(self::getAccessToken($accountId));
}
// TEST
/**
* Method to get access token from rest server.
*
* #param $accountId
* #return string
*/
private function getAccessToken($accountId)
{
return self::curlPOST('/oauth2/token', [
'client_id' => $this->config['api_app_id'],
'grant_type' => 'soap',
'scope' => 'inventory',
'developer_key' => $this->config['api_developer_key'],
'password' => $this->config['api_password'],
'account_id' => $accountId
]);
}
/**
* Method to generate a HTTP POST request
*
* #param $endpoint
* #param $fields
* #return string
*/
private function curlPOST($endpoint, $fields = array())
{
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_USERPWD, $this->config['api_app_id'] .':'. $this->config['api_shared_secret']);
curl_setopt($ch, CURLOPT_URL, self::BASE_URL . $endpoint);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded'
));
// Execute post request
$result = curl_exec($ch);
// Close connection
curl_close($ch);
// Finished
return $result;
}
}
When I execute the test($accId) method on this class, I get the following response:
boolean false
Any idea why it isn't quite working as same as the PostMan test?
P.S. I have already verified all the config/parms etc... are correct and same as my PostMan test. This class is a snipped version from my original code (created in Laravel 4.2, but this issue is not related to Laravel).
Two things:
Make sure that you send the same headers as your browser sends. For example, I don't see the Authorization-header in your code, and that one is probably quite crucial for authorizing the request on the server-side. Also for the scope you use 'inventory' instead of 'orders inventory'. Be very strict in this exercise.
Test the post-data not in an array, but write down the query-string as it should be according to yourself, this way you know there is not some issue by CURL trying to convert your array into a query-string (note, both is possible for CURL, array and query-string).
So most easy to test with:
client_id=1234&grant_type=soap&scope=order%20inventory...etc add other variables...
I have found the problem. The issue was caused by my php not being configured with curl.cainfo.
I found this by adding the following debug code to my curlPOST method like this:
private function curlPOST($endpoint, $fields = array())
{
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_USERPWD, $this->config['api_app_id'] .':'. $this->config['api_shared_secret']);
curl_setopt($ch, CURLOPT_URL, self::BASE_URL . $endpoint);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded'
));
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
// Execute post request
$result = curl_exec($ch);
// Debug error
if ($result === FALSE) {
printf("cUrl error (#%d): %s<br>\n", curl_errno($ch), htmlspecialchars(curl_error($ch)));
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Verbose information:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
}
#fclose($verbose);
// Close connection
curl_close($ch);
// Finished
return $result;
}
This outputted the following error message:
cUrl error (#60): SSL certificate problem: unable to get local issuer certificate
Verbose information:
* Hostname was found in DNS cache
* Hostname in DNS cache was stale, zapped
* Trying 216.27.89.14...
* Connected to api.channeladvisor.com (216.27.89.14) port 443 (#7)
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 7
boolean false
Which helped me track down the issue with my php.

Sending DELETE to API using PHP

I am brand new to using an API outside of an API wrapper. I can access the API using
curl -u username:password https://company.c
om/api/v1/resources/xxxxxxx
That loads up all the information, but what I need to do is send a DELETE to the url based on an array of filenames; e.g. ['/js/jquery.js']. The name of the parameter is Files.
I already have in code the directory and file name variables.
$storageFilename = $directoryname . "/" . $asset->name;
Above returns the /directoryname/filename from the database.
To send an HTTP(S) DELETE using the cURL library in PHP:
$url = 'https://url_for_your_api';
//this is the data you will send with the DELETE
$fields = array(
'field1' => urlencode('data for field1'),
'field2' => urlencode('data for field2'),
'field3' => urlencode('data for field3')
);
/*ready the data in HTTP request format
*(like the querystring in an HTTP GET, after the '?') */
$fields_string = http_build_query($fields);
//open connection
$ch = curl_init();
/*if you need to do basic authentication use these lines,
*otherwise comment them out (like, if your authenticate to your API
*by sending information in the $fields, above. */
$username = 'your_username';
$password = 'your_password';
curl_setopt($process, CURLOPT_USERPWD, $username . ":" . $password);
/*end authentication*/
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
/*unless you have installed root CAs you can't verify the remote server's
*certificate. Disable checking if this is suitable for your application*/
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//perform the HTTP DELETE
$result = curl_exec($ch);
//close connection
curl_close($ch);
/* this answer builds on David Walsh's very good HTTP POST example at:
* http://davidwalsh.name/curl-post
* modified here to make it work for HTTPS and DELETE and Authentication */

Categories