Skip to content

Instantly share code, notes, and snippets.

@ibuilder
Created March 28, 2025 22:32
Show Gist options
  • Save ibuilder/9543559dbe410a96a9b32974683c87e2 to your computer and use it in GitHub Desktop.
Save ibuilder/9543559dbe410a96a9b32974683c87e2 to your computer and use it in GitHub Desktop.
<?php
/**
* Procore API Connector
*
* A simple PHP class to authenticate and interact with the Procore API
*/
class ProcoreConnector {
private $clientId;
private $clientSecret;
private $redirectUri;
private $accessToken;
private $refreshToken;
private $tokenExpires;
private $baseUrl = 'https://api.procore.com';
private $apiVersion = 'v1.0';
/**
* Constructor
*
* @param string $clientId Your Procore API client ID
* @param string $clientSecret Your Procore API client secret
* @param string $redirectUri Your application's redirect URI
*/
public function __construct($clientId, $clientSecret, $redirectUri) {
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->redirectUri = $redirectUri;
// Check if we have a stored token
$this->loadTokenFromStorage();
}
/**
* Get authorization URL for OAuth2 flow
*
* @return string The authorization URL
*/
public function getAuthorizationUrl() {
return $this->baseUrl . '/oauth/authorize?' . http_build_query([
'client_id' => $this->clientId,
'redirect_uri' => $this->redirectUri,
'response_type' => 'code',
'scope' => 'read write'
]);
}
/**
* Exchange authorization code for tokens
*
* @param string $code The authorization code
* @return bool True if successful
*/
public function exchangeAuthorizationCode($code) {
$response = $this->makeRequest('POST', '/oauth/token', [
'grant_type' => 'authorization_code',
'code' => $code,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'redirect_uri' => $this->redirectUri
], false);
if (isset($response['access_token'])) {
$this->accessToken = $response['access_token'];
$this->refreshToken = $response['refresh_token'] ?? null;
$this->tokenExpires = time() + ($response['expires_in'] ?? 7200);
$this->saveTokenToStorage();
return true;
}
return false;
}
/**
* Refresh the access token
*
* @return bool True if successful
*/
private function refreshAccessToken() {
if (!$this->refreshToken) {
return false;
}
$response = $this->makeRequest('POST', '/oauth/token', [
'grant_type' => 'refresh_token',
'refresh_token' => $this->refreshToken,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
], false);
if (isset($response['access_token'])) {
$this->accessToken = $response['access_token'];
$this->refreshToken = $response['refresh_token'] ?? $this->refreshToken;
$this->tokenExpires = time() + ($response['expires_in'] ?? 7200);
$this->saveTokenToStorage();
return true;
}
return false;
}
/**
* Check if token is expired and refresh if needed
*
* @return bool True if we have a valid token
*/
private function ensureValidToken() {
if (!$this->accessToken) {
return false;
}
if ($this->tokenExpires <= time() + 60) {
return $this->refreshAccessToken();
}
return true;
}
/**
* Save token information to storage
*/
private function saveTokenToStorage() {
$tokenData = [
'access_token' => $this->accessToken,
'refresh_token' => $this->refreshToken,
'token_expires' => $this->tokenExpires
];
// Store token data (implement according to your needs)
// Example using file storage:
file_put_contents('procore_token.json', json_encode($tokenData));
}
/**
* Load token information from storage
*/
private function loadTokenFromStorage() {
// Retrieve token data (implement according to your needs)
// Example using file storage:
if (file_exists('procore_token.json')) {
$tokenData = json_decode(file_get_contents('procore_token.json'), true);
$this->accessToken = $tokenData['access_token'] ?? null;
$this->refreshToken = $tokenData['refresh_token'] ?? null;
$this->tokenExpires = $tokenData['token_expires'] ?? 0;
}
}
/**
* Make an API request to Procore
*
* @param string $method HTTP method (GET, POST, PUT, DELETE)
* @param string $endpoint API endpoint
* @param array $data Request data
* @param bool $requireAuth Whether authentication is required
* @return array Response data
* @throws Exception If request fails
*/
private function makeRequest($method, $endpoint, $data = [], $requireAuth = true) {
$url = $this->baseUrl;
// Add version prefix for API endpoints
if ($endpoint !== '/oauth/token') {
$url .= '/rest/' . $this->apiVersion;
}
$url .= $endpoint;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
$headers = ['Content-Type: application/json'];
if ($requireAuth) {
if (!$this->ensureValidToken()) {
throw new Exception('Authentication required but no valid token available');
}
$headers[] = 'Authorization: Bearer ' . $this->accessToken;
}
if (!empty($data)) {
if ($endpoint === '/oauth/token') {
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$headers = ['Content-Type: application/x-www-form-urlencoded'];
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
$responseData = json_decode($response, true);
if ($httpCode >= 400) {
$errorMessage = isset($responseData['errors']) ? json_encode($responseData['errors']) : 'Unknown error';
throw new Exception('API error (' . $httpCode . '): ' . $errorMessage);
}
return $responseData;
}
/**
* Get a list of projects
*
* @param array $params Optional query parameters
* @return array List of projects
*/
public function getProjects($params = []) {
return $this->makeRequest('GET', '/projects?' . http_build_query($params));
}
/**
* Get a specific project by ID
*
* @param int $projectId Project ID
* @return array Project details
*/
public function getProject($projectId) {
return $this->makeRequest('GET', '/projects/' . $projectId);
}
/**
* Get a list of companies
*
* @param array $params Optional query parameters
* @return array List of companies
*/
public function getCompanies($params = []) {
return $this->makeRequest('GET', '/companies?' . http_build_query($params));
}
/**
* Get a list of users in a project
*
* @param int $projectId Project ID
* @param array $params Optional query parameters
* @return array List of users
*/
public function getProjectUsers($projectId, $params = []) {
return $this->makeRequest('GET', '/projects/' . $projectId . '/users?' . http_build_query($params));
}
/**
* Get a list of tasks in a project
*
* @param int $projectId Project ID
* @param array $params Optional query parameters
* @return array List of tasks
*/
public function getProjectTasks($projectId, $params = []) {
return $this->makeRequest('GET', '/projects/' . $projectId . '/tasks?' . http_build_query($params));
}
/**
* Create a custom GET request to any Procore API endpoint
*
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @return array Response data
*/
public function get($endpoint, $params = []) {
$queryString = !empty($params) ? '?' . http_build_query($params) : '';
return $this->makeRequest('GET', $endpoint . $queryString);
}
/**
* Create a custom POST request to any Procore API endpoint
*
* @param string $endpoint API endpoint
* @param array $data Request data
* @return array Response data
*/
public function post($endpoint, $data = []) {
return $this->makeRequest('POST', $endpoint, $data);
}
/**
* Create a custom PUT request to any Procore API endpoint
*
* @param string $endpoint API endpoint
* @param array $data Request data
* @return array Response data
*/
public function put($endpoint, $data = []) {
return $this->makeRequest('PUT', $endpoint, $data);
}
/**
* Create a custom DELETE request to any Procore API endpoint
*
* @param string $endpoint API endpoint
* @return array Response data
*/
public function delete($endpoint) {
return $this->makeRequest('DELETE', $endpoint);
}
}
/**
* Example usage:
*/
/*
// Initialize the connector
$clientId = 'your_client_id';
$clientSecret = 'your_client_secret';
$redirectUri = 'https://your-app.com/callback';
$procore = new ProcoreConnector($clientId, $clientSecret, $redirectUri);
// If you don't have an authorization code yet
$authUrl = $procore->getAuthorizationUrl();
echo "Please visit this URL to authorize the application: " . $authUrl . "\n";
// After authorization, exchange the code for tokens
if (isset($_GET['code'])) {
$code = $_GET['code'];
if ($procore->exchangeAuthorizationCode($code)) {
echo "Authentication successful!\n";
} else {
echo "Authentication failed.\n";
}
}
// Get a list of projects
try {
$projects = $procore->getProjects();
echo "Projects:\n";
foreach ($projects as $project) {
echo "- {$project['name']} (ID: {$project['id']})\n";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
*/
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment