Skip to content

Instantly share code, notes, and snippets.

@patpawlowski
Last active June 30, 2017 03:54
Show Gist options
  • Save patpawlowski/486ea6d6b84bb6b7e90c5474ae5f001c to your computer and use it in GitHub Desktop.
Save patpawlowski/486ea6d6b84bb6b7e90c5474ae5f001c to your computer and use it in GitHub Desktop.
PHP Script to download Sugar backups from the pbs_Backups module
<?php
/**
* Created by NetBeans.
* User: patpawlowski
* Date: Mar 3, 2017 at 3:25:54 PM <- My 51st birthday ;) -pat
* File: sugarbackupdownload.php
* Create: curl https://gist.github.com/patpawlowski/486ea6d6b84bb6b7e90c5474ae5f001c/raw/ce08c191c8b3656d8749ef15c446b706a786b02b/sugarbackupdownload.php > sugarbackupdownload
* Make Executable: chmod +xxx sugarbackupdownload
* Run: php sugarbackupdownload
*/
ini_set('display_errors', 1);
class SugarAPI{
private $oauthtoken = FALSE;
private $oathrefreshtoken = '';
private $base_url = '';
private $username = '';
private $password = '';
private $starttime = '';
private $curl_error = '';
private $debug = false;
public function __construct($base_url, $username, $password)
{
if ($this->debug) echo "<pre>\nConstructor starting\n";
if(strpos($base_url, '/rest/v10')){
$this->base_url = $base_url;
}else{
$this->base_url = $base_url.'/rest/v10';
}
$this->username = $username;
$this->password = $password;
$url_ext = "/oauth2/token";
$oauth2_token_parameters = array(
"grant_type" => "password",
"client_id" => "sugar",
"client_secret" => "",
"username" => $username,
"password" => $password,
"platform" => "base"
);
$this->starttime = new DateTime(); // $this->starttime must be defined before calling "call" the first time.
$oauth2_token_result = $this->call($url_ext, 'POST', $oauth2_token_parameters);
if($oauth2_token_result)
{
$this->oauthtoken = $oauth2_token_result->access_token;
$this->oathrefreshtoken = $oauth2_token_result->refresh_token;
}else{
}
// print_r($oauth2_token_result);
if ($this->debug)
{
echo PHP_EOL.json_encode($oauth2_token_parameters).PHP_EOL;
echo "oauth2_token_result:\n";
print_r($oauth2_token_result);
echo "OAUTH Token: ".$this->oauthtoken."\n";
echo "Constructor ending\n\n";
}
}
public function search($module, $filter){
return $this->call('/'.$module, 'GET', $filter);
}
public function create($module, $record_parameters){
return $this->call('/'.$module, 'POST', $record_parameters);
}
public function read($module, $id){
return $this->call('/'.$module.'/'.$id, 'GET');
}
public function update($module, $id, $record_parameters){
return $this->call('/'.$module.'/'.$id, 'PUT', $record_parameters);
}
public function upsert($module, $record_parameters){
if(!empty($record_parameters['id'])){
$Result = $this->update($module, $record_parameters['id'], $record_parameters);
if(!(isset($Result->error) && $Result->error = 'not_found')){
return $Result;
}
}
return $this->create($module, $record_parameters);
}
public function delete($module, $id){
return $this->call('/'.$module.'/'.$id, 'DELETE');
}
public function createRelationship($module, $id, $link_name, $remote_id) {
return $this->call('/'.$module.'/'.$id.'/link/'.$link_name.'/'.$remote_id, 'POST');
}
public function readRelatedRecords($module, $id, $link_name) {
return $this->call('/'.$module.'/'.$id.'/link/'.$link_name);
}
public function deleteRelationship($module, $id, $link_name, $remote_id) {
return $this->call('/'.$module.'/'.$id.'/link/'.$link_name.'/'.$remote_id, 'DELETE');
}
public function bulkAPICall($parameters) {
return $this->call('/bulk', 'POST', $parameters);
}
public function getOathToken()
{
return $this->oauthtoken;
}
public function checkID($module, $id) {
$Return = $this->read($module, $id);
if(isset($Return->id)){
return TRUE;
}else{
return FALSE;
}
}
/**
* Generic function to make cURL request.
* @param $url - The URL route to use.
* @param string $oauthtoken - The oauth token.
* @param string $type - GET, POST, PUT. Defaults to GET.
* @param array $parameters - Endpoint parameters.
* @param array $encodeData - Whether or not to JSON encode the data.
* @param array $returnHeaders - Whether or not to return the headers.
* @return mixed
*/
public function call(
$url_ext,
$type = 'GET',
$parameters=array(),
$encodeData=true,
$returnHeaders=false
)
{
if ($this->debug)
{
echo "call function starting\n";
echo "url_ext: ".$type."\n";
echo "type: ".$url_ext."\n";
echo "parameters: \n";
print_r($parameters);
}
// Check for OAUTH Token Expiration
$this->checkToken();
$url = $this->base_url.$url_ext;
$oauthtoken = $this->oauthtoken;
$type = strtoupper($type);
if ($type == 'GET')
{
if(is_array($parameters))
{
$url .= "?" . http_build_query($parameters);
}
}
/*
* $filter_arguments = array(
* "filter" => array(
* array(
* "name" => 'ACME, Inc.'
* ),
* ),
* "max_num" => 2,
* "offset" => 0,
* "fields" => "name,description",
* "order_by" => "name:DESC",
* "favorites" => false,
* "my_items" => false,
* );
*/
if ($this->debug) echo "CURL URL: ".$url."\n";
$curl_request = curl_init($url);
if ($type == 'POST')
{
curl_setopt($curl_request, CURLOPT_POST, 1);
}
elseif ($type == 'PUT')
{
curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "PUT");
}
elseif ($type == 'DELETE')
{
curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "DELETE");
}
curl_setopt($curl_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl_request, CURLOPT_HEADER, $returnHeaders);
curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_request, CURLOPT_FOLLOWLOCATION, 0);
$header = array('Content-Type: application/json');
if (!empty($oauthtoken))
{
$header[] = "oauth-token: $oauthtoken";
}
curl_setopt($curl_request, CURLOPT_HTTPHEADER, $header);
if (!empty($parameters) && $type !== 'GET')
{
if ($encodeData)
{
//encode the parameters as JSON
$parameters = json_encode($parameters);
}
curl_setopt($curl_request, CURLOPT_POSTFIELDS, $parameters);
}
$result = curl_exec($curl_request);
if(!$result)
{
$this->curl_error = curl_error($curl_request);
}
if ($this->debug)
{
echo "Raw CURL response:\n";
print_r($result);
echo "CURL ERROR: ".curl_error($curl_request);
}
if ($returnHeaders)
{
//set headers from response
list($headers, $content) = explode("\r\n\r\n", $result ,2);
foreach (explode("\r\n",$headers) as $header)
{
header($header);
}
//return the nonheader data
return trim($content);
}
curl_close($curl_request);
//decode the response from JSON
$response = json_decode($result);
if ($this->debug) echo "\ncall function ending\n";
return $response;
}
private function refreshToken()
{
// $this->starttime must be reset before calling $this->call or an endless loop will be initiated
$Now = new DateTime();
$this->starttime = $Now;
$this->oauthtoken = FALSE;
$url_ext = "/oauth2/token";
$oauth2_token_parameters = array(
"grant_type" => "refresh_token",
"refresh_token" => $this->oathrefreshtoken,
"client_id" => "sugar",
"client_secret" => ""
);
$oauth2_token_result = $this->call($url_ext, 'POST', $oauth2_token_parameters);
print_r($oauth2_token_result);
$this->oauthtoken = $oauth2_token_result->access_token;
$this->oathrefreshtoken = $oauth2_token_result->refresh_token;
echo "OAUTH Token refreshed\n";
}
public function checkToken()
{
$Now = new DateTime();
$TokenAge = date_diff($this->starttime, $Now, true);
if ($TokenAge->i > 59 || $TokenAge->h > 0)
{
echo "OAUTH Token about to expire. Refreshing. . . \n";
$this->refreshToken();
}
}
public function isConnected() {
if($this->oauthtoken)
{
return TRUE;
} else {
return FALSE;
}
}
public function getCurlError() {
return $this->curl_error;
}
}
class SugarBackupDownloader {
private $BaseURL = '';
private $UserName = '';
private $Password = '';
private $APIURL = '';
private $SugarAPI = false;
private $Backups = array();
public function __construct() {
$this->getConnectionParameters();
$this->loadBackups();
$this->getBackupNumber();
}
public function getConnectionParameters() {
echo "Enter base URL. ex: https://mysugar.sugarondemand.com:> ";
$BaseURL = trim(fgets(STDIN));
echo "Enter username:> ";
$UserName = trim(fgets(STDIN));
echo "Enter password:> ";
system('stty -echo');
$Password = trim(fgets(STDIN));
system('stty echo');
$this->BaseURL = $BaseURL;
$this->UserName = $UserName;
$this->Password = $Password;
$this->APIURL = $this->BaseURL . '/rest/v10';
echo "Connecting to Sugar and getting list of backups . . . \n";
$this->SugarAPI = new SugarAPI($this->APIURL, $this->UserName, $this->Password);
}
private function loadBackups() {
$Result = $this->SugarAPI->search('ops_Backups', array());
$this->Backups = $Result->records;
// print_r($Result);
}
private function getBackupNumber() {
foreach($this->Backups as $Index => $Backup){
echo "$Index \t $Backup->name $Backup->date_entered\n";
}
echo "\n\tEnter the number of the backup to download:> ";
$BackupNumber = trim(fgets(STDIN)); // reads one line from STDIN
$this->downloadBackup($BackupNumber);
}
private function downloadBackup($BackupNumber) {
echo $this->Backups[$BackupNumber]->download_url.PHP_EOL;
$URL = $this->Backups[$BackupNumber]->download_url;
$Filename = basename($URL);
exec("wget $URL -O $Filename");
}
}
$SugarBackupDownloader = new SugarBackupDownloader();
@patpawlowski
Copy link
Author

patpawlowski commented Jun 26, 2017

I don't know about everyone else but when I need to download a Sugar backup it's usually to a headless Linux machine and not to a machine with a UI and a browser. I created this script for just that.

You can download it from here or just run

curl https://gist.github.com/patpawlowski/486ea6d6b84bb6b7e90c5474ae5f001c/raw/ce08c191c8b3656d8749ef15c446b706a786b02b/sugarbackupdownload.php > sugarbackupdownload

Make it executable:

chmod +xxx sugarbackupdownload 

And then run it:

php sugarbackupdownload

Enter base URL. ex: https://mysugar.sugarondemand.com:> https://mysugar.sugarondemand.com

Enter username:> Ticomix

Enter password:> SomePassword

Connecting to Sugar and getting list of backups . . .
0 mysugar.sugarondemand.com - 7821ent 2017-06-26T00:26:33+00:00
1 mysugar.sugarondemand.com - 7820ent 2017-05-02T20:50:31+00:00

Enter the number of the backup to download:> 0

Connecting to xxxxxxxxxx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 59485709 (57M) [binary/octet-stream]
Saving to: `mysugar.sugarondemand.com.7821ent.1498436798.ca3984af5135c32c706fd36cf6e47ba0cae7c840.tar.gz'

100%[====================================================================================================================>] 59,485,709 18.6M/s in 3.0s

2017-06-26 10:02:54 (18.6 MB/s) - `mysugar.sugarondemand.com.7821ent.1498436798.ca3984af5135c32c706fd36cf6e47ba0cae7c840.tar.gz' saved [59485709/59485709]

And that's all there is to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment