Skip to content

Instantly share code, notes, and snippets.

@jasonrush
Last active June 3, 2021 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonrush/98cfe641a3496d0d97b34bd3ca0b66cd to your computer and use it in GitHub Desktop.
Save jasonrush/98cfe641a3496d0d97b34bd3ca0b66cd to your computer and use it in GitHub Desktop.
A quick PHP class to get information about open tickets on Spiceworks Cloud HelpDesk.
<?php
class spiceworks {
// Information used to log in and get ticket info.
private $loginURL = 'https://accounts.spiceworks.com/sign_in';
private $dataURLOpen = 'https://on.spiceworks.com/api/tickets?filter%5Bstatus%5D%5Beq%5D=open';
private $dataURLWaiting = 'https://on.spiceworks.com/api/tickets?filter%5Bstatus%5D%5Beq%5D=waiting';
private $cookiePath = '';
private $authToken = '';
private $isLoggedIn = false;
// Information set by users to log in.
private $useragent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2';
private $user = "";
private $pass = "";
// Information returned from Spiceworks to be consumed by users.
public $users = null;
public $tickets = null;
// Basic constructor, allowing requesting username and password, and optionally tell it to gather info immediately.
function __construct( $username = "", $password = "", $loadInfo = false ){
if( "" != $username ){
$this->setUser( $username );
}
if( "" != $password ){
$this->setPass( $password );
}
if( $loadInfo ){
$this->loadInfo();
}
}
public function setUser( $username ){
$this->user = $username;
}
public function setPass( $password ){
$this->pass = $password;
}
public function setUseragent( $useragent ){
$this->useragent = $useragent;
}
private function setCookiePath(){
if( '' == $this->cookiePath){
$convertedEmail = str_replace( '@', '__', $this->user );
$this->cookiePath = sys_get_temp_dir() . "/php_curl_$convertedEmail.txt";
}
}
public function findToken(){
$this->setCookiePath();
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $this->loginURL );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_AUTOREFERER, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_USERAGENT, $this->useragent );
curl_setopt( $ch, CURLOPT_COOKIEJAR, $this->cookiePath );
curl_setopt( $ch, CURLOPT_COOKIEFILE, $this->cookiePath );
$result = curl_exec( $ch );
curl_close( $ch );
// Request the signin page so we can get an authenticity token
// Search the HTML code for 'name="authenticity_token"', then find 'value="xxxxxx"' to get the token.
// <form class="form-vertical login-form" action="/sign_in" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="JPjU9FvfmwoxpcsobwdgTQKPh6EmKgCnInHqvEUwMT7umhoAHRYa6BVn36tjoLIiifjN4v/taUpAdrZYXkVI8w==" />
$lines = explode( PHP_EOL, $result );
// Find line with token.
foreach( $lines as $line ){
if( false !== strpos( $line, 'name="authenticity_token"')){
$tokenLine = $line;
break;
}
}
// If this line is found, we are already logged in (using the cookie file).
if( false !== strpos( $result, '<li><a href="/users/reset_password_request">reset your password</a></li>' ) ){
$this->isLoggedIn = true;
return;
}
// Find token within line.
$tokenSearchStart = strpos( $tokenLine, 'name="authenticity_token"' ) + 25;
$tokenStart = strpos( $tokenLine, 'value="', $tokenSearchStart ) + 7;
$tokenEnd = strpos( $tokenLine, '"', $tokenStart + 1 );
// Save token.
$this->authToken = substr( $tokenLine, $tokenStart, $tokenEnd - $tokenStart );
}
public function login( $username = "", $password = "" ){
// If a token hasn't been found yet, get an authentication token.
if( ! $this->isLoggedIn && '' == $this->authToken ){
$this->findToken();
}
if( "" != $username ){
$this->setUser( $username );
}
if( "" != $password ){
$this->setPass( $password );
}
// Cookie path is based on username, and we need the cookie path set to properly login.
$this->setCookiePath();
// Submit the signin form
$formData = array(
'utf8' => '✓',
'authenticity_token' => $this->authToken,
'email' => $this->user,
'password' => $this->pass,
'success' => 'https://on.spiceworks.com/auth/spiceworks/callback',
'permission_denied' => 'https://accounts.spiceworks.com/',
'policy' => 'hosted_help_desk',
'commit' => 'Log+in',
);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $this->loginURL );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_AUTOREFERER, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $formData );
curl_setopt( $ch, CURLOPT_USERAGENT, $this->useragent );
curl_setopt( $ch, CURLOPT_COOKIEJAR, $this->cookiePath );
curl_setopt( $ch, CURLOPT_COOKIEFILE, $this->cookiePath );
$result = curl_exec( $ch );
curl_close( $ch );
if( false !== strpos( $result, '<script id="data" type="application/json">' ) ){
$this->isLoggedIn = true;
}
return $this->isLoggedIn;
}
// Page through users and tickets JSON data and save to the appropriate object properties.
public function loadInfo(){
if( ! $this->isLoggedIn ){
$this->login() or die( 'Login failed within loadInfo()' );
}
// Cycle through open tickets
$page = 1;
$readMorePages = true;
while( $readMorePages ){
$ch = curl_init();
$pagedURL = $this->dataURLOpen;
if( $page > 1 ){
$pagedURL .= "&page=$page";
}
curl_setopt( $ch, CURLOPT_URL, $pagedURL );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_AUTOREFERER, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_USERAGENT, $this->useragent );
curl_setopt( $ch, CURLOPT_COOKIEJAR, $this->cookiePath );
curl_setopt( $ch, CURLOPT_COOKIEFILE, $this->cookiePath );
$result = curl_exec( $ch );
curl_close( $ch );
$parseCount = $this->parseJsonString( $result );
if( 0 == $parseCount ){
$readMorePages = false;
}
$page++;
}
// Cycle through Waiting tickets
$page = 1;
$readMorePages = true;
while( $readMorePages ){
$ch = curl_init();
$pagedURL = $this->dataURLWaiting;
if( $page > 1 ){
$pagedURL .= "&page=$page";
}
curl_setopt( $ch, CURLOPT_URL, $pagedURL );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_AUTOREFERER, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_USERAGENT, $this->useragent );
curl_setopt( $ch, CURLOPT_COOKIEJAR, $this->cookiePath );
curl_setopt( $ch, CURLOPT_COOKIEFILE, $this->cookiePath );
$result = curl_exec( $ch );
curl_close( $ch );
$parseCount = $this->parseJsonString( $result );
if( 0 == $parseCount ){
$readMorePages = false;
}
$page++;
}
}
// For each page of JSON data passed, parse through it and add any new users and/or tickets.
private function parseJsonString( $jsonString ){
$jsonData = json_decode( $jsonString );
// Track how many new users/tickets are parsed so we can tell if we've hit an empty page.
$parseCount = 0;
// Add all types of users to $users property, indexed by ID.
// If there are no more pages, the assorted user object properties aren't even set, just an empty Tickets property.
if( isset( $jsonData->users ) ){
foreach( $jsonData->users as $user ){
if( ! isset( $this->users[ $user->id ] ) ){
$this->users[ $user->id ] = $user;
$parseCount++;
}
}
}
if( isset( $jsonData->archived_users ) ){
foreach( $jsonData->archived_users as $user ){
if( ! isset( $this->users[ $user->id ] ) ){
$this->users[ $user->id ] = $user;
$parseCount++;
}
}
}
if( isset( $jsonData->end_users ) ){
foreach( $jsonData->end_users as $user ){
if( ! isset( $this->users[ $user->id ] ) ){
$this->users[ $user->id ] = $user;
$parseCount++;
}
}
}
// Allow accessing tickets by ID.
foreach( $jsonData->tickets as $ticket ){
if( ! isset( $this->tickets[ $ticket->id ] ) ){
$ticket->creator->first_name = $this->users[ $ticket->creator->id ]->first_name;
$ticket->creator->last_name = $this->users[ $ticket->creator->id ]->last_name;
$ticket->creator->name = $this->users[ $ticket->creator->id ]->name;
$ticket->creator->email = $this->users[ $ticket->creator->id ]->email;
if( isset( $this->users[ $ticket->creator->id ]->phone_number ) ){
$ticket->creator->phone_number = $this->users[ $ticket->creator->id ]->phone_number;
}
$this->tickets[ $ticket->id ] = $ticket;
$parseCount++;
}
}
return $parseCount;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment