Added missing getAccessToken() method to BoxClient
Fixed BoxFileRetriever to properly initialize BoxClient with credentials from config
Changes:
- BoxClient: Added public getAccessToken() method
- BoxFileRetriever: Load Box config and extract clientID/clientSecret
- BoxFileRetriever: Pass credentials to BoxClient constructor
This fixes the 'Call to undefined method' error when loading Box files.
🤖 Generated with Claude Code
323 lines
9 KiB
PHP
323 lines
9 KiB
PHP
<?php
|
|
|
|
require_once 'BoxClient.php';
|
|
|
|
/**
|
|
* BoxFileRetriever - List and Download Files from Box Folders
|
|
*
|
|
* This class handles:
|
|
* 1. Listing files in a Box folder
|
|
* 2. Getting file metadata
|
|
* 3. Downloading files to temp location
|
|
* 4. Extracting tracking IDs from filenames
|
|
*/
|
|
class BoxFileRetriever
|
|
{
|
|
private $boxClient;
|
|
private $tempDir;
|
|
|
|
public function __construct($boxConfigFile = 'Box-config.json')
|
|
{
|
|
// Load Box config
|
|
$configPath = __DIR__ . '/../' . $boxConfigFile;
|
|
if (!file_exists($configPath)) {
|
|
throw new Exception("Box config file not found: $configPath");
|
|
}
|
|
|
|
$config = json_decode(file_get_contents($configPath), true);
|
|
$clientId = $config['boxAppSettings']['clientID'] ?? null;
|
|
$clientSecret = $config['boxAppSettings']['clientSecret'] ?? null;
|
|
|
|
if (!$clientId || !$clientSecret) {
|
|
throw new Exception("Box config missing clientID or clientSecret");
|
|
}
|
|
|
|
// Initialize BoxClient with credentials
|
|
$this->boxClient = new BoxClient($clientId, $clientSecret);
|
|
$this->tempDir = sys_get_temp_dir() . '/ferrero_box_downloads';
|
|
|
|
// Create temp directory if it doesn't exist
|
|
if (!is_dir($this->tempDir)) {
|
|
mkdir($this->tempDir, 0755, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* List all files in a Box folder
|
|
*
|
|
* @param string $folderId Box folder ID
|
|
* @return array List of files with metadata
|
|
*/
|
|
public function listFilesInFolder($folderId)
|
|
{
|
|
try {
|
|
$accessToken = $this->boxClient->getAccessToken();
|
|
|
|
// Call Box API to list folder items
|
|
$url = "https://api.box.com/2.0/folders/$folderId/items?fields=id,name,type,size,modified_at,description";
|
|
|
|
$ch = curl_init();
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => [
|
|
'Authorization: Bearer ' . $accessToken,
|
|
'Content-Type: application/json'
|
|
],
|
|
CURLOPT_TIMEOUT => 60
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($error) {
|
|
throw new Exception("Box API error: $error");
|
|
}
|
|
|
|
if ($httpCode !== 200) {
|
|
throw new Exception("Box API returned HTTP $httpCode: $response");
|
|
}
|
|
|
|
$data = json_decode($response, true);
|
|
|
|
if (!isset($data['entries'])) {
|
|
throw new Exception("Invalid response from Box API");
|
|
}
|
|
|
|
// Filter to only files (not folders)
|
|
$files = [];
|
|
foreach ($data['entries'] as $item) {
|
|
if ($item['type'] === 'file') {
|
|
$files[] = [
|
|
'id' => $item['id'],
|
|
'name' => $item['name'],
|
|
'size' => $item['size'] ?? 0,
|
|
'modified_at' => $item['modified_at'] ?? null,
|
|
'description' => $item['description'] ?? '',
|
|
'box_url' => "https://app.box.com/file/{$item['id']}"
|
|
];
|
|
}
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'folder_id' => $folderId,
|
|
'file_count' => count($files),
|
|
'files' => $files
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage(),
|
|
'folder_id' => $folderId
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get metadata for a specific file
|
|
*
|
|
* @param string $fileId Box file ID
|
|
* @return array File metadata
|
|
*/
|
|
public function getFileMetadata($fileId)
|
|
{
|
|
try {
|
|
$accessToken = $this->boxClient->getAccessToken();
|
|
|
|
$url = "https://api.box.com/2.0/files/$fileId?fields=id,name,type,size,modified_at,description,created_at,shared_link";
|
|
|
|
$ch = curl_init();
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => [
|
|
'Authorization: Bearer ' . $accessToken,
|
|
'Content-Type: application/json'
|
|
],
|
|
CURLOPT_TIMEOUT => 30
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode !== 200) {
|
|
throw new Exception("Box API returned HTTP $httpCode");
|
|
}
|
|
|
|
$data = json_decode($response, true);
|
|
|
|
return [
|
|
'success' => true,
|
|
'metadata' => $data
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Download a file from Box
|
|
*
|
|
* @param string $fileId Box file ID
|
|
* @param string $filename Filename for local save
|
|
* @return array Result with local path
|
|
*/
|
|
public function downloadFile($fileId, $filename)
|
|
{
|
|
try {
|
|
$accessToken = $this->boxClient->getAccessToken();
|
|
|
|
// Download URL
|
|
$url = "https://api.box.com/2.0/files/$fileId/content";
|
|
|
|
$localPath = $this->tempDir . '/' . $filename;
|
|
|
|
// Download file
|
|
$ch = curl_init();
|
|
$fp = fopen($localPath, 'w');
|
|
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_HTTPHEADER => [
|
|
'Authorization: Bearer ' . $accessToken
|
|
],
|
|
CURLOPT_FILE => $fp,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_TIMEOUT => 300
|
|
]);
|
|
|
|
$result = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
fclose($fp);
|
|
|
|
if (!$result || $httpCode !== 200) {
|
|
unlink($localPath);
|
|
throw new Exception("Download failed with HTTP $httpCode");
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'local_path' => $localPath,
|
|
'size' => filesize($localPath)
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract tracking ID from filename
|
|
*
|
|
* @param string $filename Full filename
|
|
* @return string|null Tracking ID or null if not found
|
|
*/
|
|
public function extractTrackingId($filename)
|
|
{
|
|
// Remove extension
|
|
$pathInfo = pathinfo($filename);
|
|
$filenameWithoutExt = $pathInfo['filename'];
|
|
|
|
// Split by underscore
|
|
$parts = explode('_', $filenameWithoutExt);
|
|
|
|
// Last part should be tracking ID (6 alphanumeric characters)
|
|
if (count($parts) > 0) {
|
|
$lastPart = end($parts);
|
|
if (strlen($lastPart) === 6 && ctype_alnum($lastPart)) {
|
|
return $lastPart;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* List files with parsed tracking IDs
|
|
*
|
|
* @param string $folderId Box folder ID
|
|
* @return array Files with tracking ID info
|
|
*/
|
|
public function listFilesWithTrackingIDs($folderId)
|
|
{
|
|
$result = $this->listFilesInFolder($folderId);
|
|
|
|
if (!$result['success']) {
|
|
return $result;
|
|
}
|
|
|
|
// Add tracking ID to each file
|
|
foreach ($result['files'] as &$file) {
|
|
$file['tracking_id'] = $this->extractTrackingId($file['name']);
|
|
$file['has_tracking_id'] = !empty($file['tracking_id']);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get temp directory path
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTempDir()
|
|
{
|
|
return $this->tempDir;
|
|
}
|
|
|
|
/**
|
|
* Clean up temp directory
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function cleanTempDir()
|
|
{
|
|
if (!is_dir($this->tempDir)) {
|
|
return true;
|
|
}
|
|
|
|
$files = glob($this->tempDir . '/*');
|
|
foreach ($files as $file) {
|
|
if (is_file($file)) {
|
|
unlink($file);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Test Box connection
|
|
*
|
|
* @return array
|
|
*/
|
|
public function testConnection()
|
|
{
|
|
try {
|
|
$accessToken = $this->boxClient->getAccessToken();
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Box connection successful',
|
|
'has_token' => !empty($accessToken)
|
|
];
|
|
} catch (Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
}
|