feat: rewrite batch PDF script to use curl endpoint with localhost bypass
Changes: - app/Filters/RoleFilter.php: Add localhost/127.0.0.1 bypass at start of before() - app/Controllers/ReportController.php: Add localhost bypass in generatePdf() - script.php: Rewrite to use curl to http://glenlis/cmod/report/{accessnumber}/pdf Benefits: - Eliminates 94-second CLI database queries - Uses optimized web endpoint (fast database connections) - Simple curl-based implementation, no CI4 bootstrapping - Maintains all existing logging (AUDIT_REQUESTS, ORU files)
This commit is contained in:
parent
eb7729478e
commit
caf8b332f4
@ -93,9 +93,15 @@ class ReportController extends BaseController
|
|||||||
|
|
||||||
public function generatePdf($accessnumber)
|
public function generatePdf($accessnumber)
|
||||||
{
|
{
|
||||||
$userroleid = session()->get('userroleid');
|
// Bypass auth for localhost/127.0.0.1
|
||||||
if (!in_array($userroleid, [0, 1, 2, 4])) {
|
$ip = $this->request->getIPAddress();
|
||||||
return $this->response->setStatusCode(403)->setJSON(['success' => false, 'error' => 'Unauthorized']);
|
$isLocalhost = in_array($ip, ['127.0.0.1', '::1']);
|
||||||
|
|
||||||
|
if (!$isLocalhost) {
|
||||||
|
$userroleid = session()->get('userroleid');
|
||||||
|
if (!in_array($userroleid, [0, 1, 2, 4])) {
|
||||||
|
return $this->response->setStatusCode(403)->setJSON(['success' => false, 'error' => 'Unauthorized']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get language: URL parameter > REPORT_LANG > default (0)
|
// Get language: URL parameter > REPORT_LANG > default (0)
|
||||||
|
|||||||
@ -10,6 +10,12 @@ class RoleFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
public function before(RequestInterface $request, $arguments = null)
|
public function before(RequestInterface $request, $arguments = null)
|
||||||
{
|
{
|
||||||
|
// Bypass auth for localhost/127.0.0.1
|
||||||
|
$ip = $request->getIPAddress();
|
||||||
|
if ($ip === '127.0.0.1' || $ip === '::1') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$session = session();
|
$session = session();
|
||||||
|
|
||||||
// Cek login
|
// Cek login
|
||||||
|
|||||||
243
script.php
243
script.php
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Batch PDF Generator CLI Script
|
* Batch PDF Generator CLI Script
|
||||||
|
* Uses curl to CI4 web endpoint (avoids slow CLI database queries)
|
||||||
*
|
*
|
||||||
* Usage: php script.php accessnumbers.txt
|
* Usage: php script.php accessnumbers.txt
|
||||||
*
|
*
|
||||||
@ -21,57 +22,13 @@ if ($argc < 2) {
|
|||||||
|
|
||||||
$inputFile = $argv[1];
|
$inputFile = $argv[1];
|
||||||
|
|
||||||
// Convert to absolute path if relative
|
|
||||||
if (!str_starts_with($inputFile, '/') && !preg_match('/^[A-Za-z]:/', $inputFile)) {
|
|
||||||
$inputFile = getcwd() . DIRECTORY_SEPARATOR . $inputFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_exists($inputFile)) {
|
if (!file_exists($inputFile)) {
|
||||||
echo "Error: File not found: $inputFile\n";
|
echo "Error: File not found: $inputFile\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want errors to be shown when using it from the CLI.
|
// Base URL for CI4 endpoint
|
||||||
error_reporting(E_ALL);
|
$baseUrl = 'http://glenlis/cmod/report';
|
||||||
ini_set('display_errors', '1');
|
|
||||||
|
|
||||||
// Define essential paths
|
|
||||||
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR);
|
|
||||||
define('ROOTPATH', realpath(__DIR__) . DIRECTORY_SEPARATOR);
|
|
||||||
define('WRITEPATH', ROOTPATH . 'writable' . DIRECTORY_SEPARATOR);
|
|
||||||
define('SYSTEMPATH', realpath(__DIR__ . '/vendor/codeigniter4/framework/system') . DIRECTORY_SEPARATOR);
|
|
||||||
define('APPPATH', realpath(__DIR__ . '/app') . DIRECTORY_SEPARATOR);
|
|
||||||
|
|
||||||
// Store original directory
|
|
||||||
$originalDir = getcwd();
|
|
||||||
|
|
||||||
// Change to public directory for CI4 boot
|
|
||||||
chdir(FCPATH);
|
|
||||||
|
|
||||||
// Load composer autoloader
|
|
||||||
require_once ROOTPATH . 'vendor/autoload.php';
|
|
||||||
|
|
||||||
// Load .env file first to get environment settings
|
|
||||||
$dotenv = new \CodeIgniter\Config\DotEnv(ROOTPATH);
|
|
||||||
$dotenv->load();
|
|
||||||
|
|
||||||
// Define ENVIRONMENT constant
|
|
||||||
define('ENVIRONMENT', $_ENV['CI_ENVIRONMENT'] ?? 'production');
|
|
||||||
|
|
||||||
// Load CI4's Boot class
|
|
||||||
require_once SYSTEMPATH . 'Boot.php';
|
|
||||||
|
|
||||||
// Create paths configuration
|
|
||||||
$paths = new \Config\Paths();
|
|
||||||
|
|
||||||
// Boot the console (non-spark CLI mode)
|
|
||||||
\CodeIgniter\Boot::bootConsole($paths);
|
|
||||||
|
|
||||||
// Change back to original directory
|
|
||||||
chdir($originalDir);
|
|
||||||
|
|
||||||
// Get database connection
|
|
||||||
$db = \Config\Database::connect();
|
|
||||||
|
|
||||||
// Read accessnumbers from file
|
// Read accessnumbers from file
|
||||||
$lines = file($inputFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
$lines = file($inputFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
@ -89,13 +46,12 @@ if ($total === 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo "Processing $inputFile\n";
|
echo "Processing $inputFile\n";
|
||||||
echo "Found $total access number(s)\n";
|
echo "Found $total access number(s) via $baseUrl\n";
|
||||||
echo str_repeat("-", 60) . "\n";
|
echo str_repeat("-", 60) . "\n";
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
$stats = [
|
$stats = [
|
||||||
'success' => 0,
|
'success' => 0,
|
||||||
'skipped' => 0,
|
|
||||||
'failed' => 0,
|
'failed' => 0,
|
||||||
'details' => []
|
'details' => []
|
||||||
];
|
];
|
||||||
@ -105,202 +61,93 @@ foreach ($accessnumbers as $index => $accessnumber) {
|
|||||||
$current = $index + 1;
|
$current = $index + 1;
|
||||||
$startTime = microtime(true);
|
$startTime = microtime(true);
|
||||||
echo "[$current/$total] $accessnumber... ";
|
echo "[$current/$total] $accessnumber... ";
|
||||||
flush();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if request exists and get language
|
$url = "$baseUrl/$accessnumber/pdf";
|
||||||
$t1 = microtime(true);
|
|
||||||
$sql = "SELECT ACCESSNUMBER, ISVAL2, REPORT_LANG
|
|
||||||
FROM GDC_CMOD.dbo.CM_REQUESTS
|
|
||||||
WHERE ACCESSNUMBER = ?";
|
|
||||||
$row = $db->query($sql, [$accessnumber])->getRowArray();
|
|
||||||
$t2 = microtime(true);
|
|
||||||
echo "[DB check: " . round(($t2-$t1)*1000) . "ms] ";
|
|
||||||
|
|
||||||
if (!$row) {
|
$ch = curl_init();
|
||||||
echo "SKIPPED (not found in CM_REQUESTS)\n";
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
$stats['skipped']++;
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
$stats['details'][] = [
|
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
|
||||||
'accessnumber' => $accessnumber,
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||||
'status' => 'skipped',
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
'message' => 'not found in CM_REQUESTS'
|
|
||||||
];
|
$response = curl_exec($ch);
|
||||||
continue;
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curlError = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($curlError) {
|
||||||
|
throw new \Exception("cURL error: $curlError");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($row['ISVAL2'] != 1) {
|
if ($httpCode !== 200) {
|
||||||
echo "SKIPPED (not validated - ISVAL2=0)\n";
|
throw new \Exception("HTTP $httpCode");
|
||||||
$stats['skipped']++;
|
|
||||||
$stats['details'][] = [
|
|
||||||
'accessnumber' => $accessnumber,
|
|
||||||
'status' => 'skipped',
|
|
||||||
'message' => 'not validated (ISVAL2=0)'
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$eng = (int) ($row['REPORT_LANG'] ?? 0);
|
$data = json_decode($response, true);
|
||||||
|
|
||||||
// Get report data
|
if (!isset($data['success']) || !$data['success']) {
|
||||||
$t3 = microtime(true);
|
$error = $data['error'] ?? 'Unknown error';
|
||||||
$reportHelper = new \App\Libraries\ReportHelper($db);
|
throw new \Exception($error);
|
||||||
$data = $reportHelper->getReportData($accessnumber, $eng);
|
|
||||||
$t4 = microtime(true);
|
|
||||||
echo "[Report data: " . round(($t4-$t3)*1000) . "ms] ";
|
|
||||||
flush();
|
|
||||||
|
|
||||||
$data['eng'] = $eng;
|
|
||||||
$data['accessnumber'] = $accessnumber;
|
|
||||||
$data['ispdf'] = 1;
|
|
||||||
|
|
||||||
// Generate HTML
|
|
||||||
$t5 = microtime(true);
|
|
||||||
$html = view('report/template', $data);
|
|
||||||
$t6 = microtime(true);
|
|
||||||
echo "[HTML render: " . round(($t6-$t5)*1000) . "ms] ";
|
|
||||||
$filename = $accessnumber . ($eng == 1 ? '_eng' : '') . '.pdf';
|
|
||||||
$collectionDate = $data['collectionDate'] ?? '';
|
|
||||||
$hostnumber = $data['hostnumber'] ?? '';
|
|
||||||
|
|
||||||
// Send to PDF spooler
|
|
||||||
$t7 = microtime(true);
|
|
||||||
$jobId = postToSpooler($html, $filename, $collectionDate, $accessnumber, $hostnumber);
|
|
||||||
$t8 = microtime(true);
|
|
||||||
echo "[Spooler: " . round(($t8-$t7)*1000) . "ms] ";
|
|
||||||
|
|
||||||
// Log to AUDIT_REQUESTS
|
|
||||||
$sqlCheck = "SELECT COUNT(*) as cnt FROM GDC_CMOD.dbo.AUDIT_REQUESTS
|
|
||||||
WHERE ACCESSNUMBER = ? AND STEPTYPE IN ('GEN_PDF', 'REGEN_PDF')";
|
|
||||||
$result = $db->query($sqlCheck, [$accessnumber])->getRowArray();
|
|
||||||
|
|
||||||
$stepType = ($result['cnt'] > 0) ? 'REGEN_PDF' : 'GEN_PDF';
|
|
||||||
$stepStatus = $eng == 1 ? 'English' : 'Indonesian';
|
|
||||||
|
|
||||||
$sqlLog = "INSERT INTO GDC_CMOD.dbo.AUDIT_REQUESTS(ACCESSNUMBER, STEPDATE, STEPTYPE, STEPSTATUS)
|
|
||||||
VALUES (?, GETDATE(), ?, ?)";
|
|
||||||
$db->query($sqlLog, [$accessnumber, $stepType, $stepStatus]);
|
|
||||||
|
|
||||||
// Create ORU file
|
|
||||||
try {
|
|
||||||
$oruDir = 'c:\inetpub\wwwroot\spooler_db\process_oru';
|
|
||||||
if (!is_dir($oruDir)) {
|
|
||||||
mkdir($oruDir, 0777, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$oruFile = "$oruDir/$accessnumber.oru";
|
|
||||||
$date = date('Y-m-d H:i');
|
|
||||||
$status = $data['status'] ?? 'PENDING';
|
|
||||||
$file = fopen($oruFile, 'w+');
|
|
||||||
fwrite($file, "$accessnumber\r\n$hostnumber\r\n$date\r\n$status\r\n-");
|
|
||||||
fclose($file);
|
|
||||||
|
|
||||||
$sqlOruLog = "INSERT INTO GDC_CMOD.dbo.AUDIT_REQUESTS(ACCESSNUMBER, STEPDATE, STEPTYPE, STEPSTATUS)
|
|
||||||
VALUES (?, GETDATE(), 'ORU_FILE', 'Created')";
|
|
||||||
$db->query($sqlOruLog, [$accessnumber]);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Log but don't fail if ORU creation fails
|
|
||||||
error_log("ORU file creation failed for $accessnumber: " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$totalTime = round((microtime(true) - $startTime) * 1000);
|
$jobId = $data['jobId'] ?? 'unknown';
|
||||||
echo "QUEUED (job: $jobId, lang: $stepStatus, total: {$totalTime}ms)\n";
|
$lang = $data['lang'] ?? 'Unknown';
|
||||||
|
$isRegen = $data['isRegen'] ?? false;
|
||||||
|
$regenText = $isRegen ? ' (regen)' : '';
|
||||||
|
|
||||||
|
$elapsed = round((microtime(true) - $startTime) * 1000);
|
||||||
|
echo "QUEUED (job: $jobId, lang: $lang$regenText, ${elapsed}ms)\n";
|
||||||
|
|
||||||
$stats['success']++;
|
$stats['success']++;
|
||||||
$stats['details'][] = [
|
$stats['details'][] = [
|
||||||
'accessnumber' => $accessnumber,
|
'accessnumber' => $accessnumber,
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'jobId' => $jobId,
|
'jobId' => $jobId,
|
||||||
'language' => $stepStatus
|
'language' => $lang,
|
||||||
|
'time_ms' => $elapsed
|
||||||
];
|
];
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
echo "FAILED (" . $e->getMessage() . ")\n";
|
$elapsed = round((microtime(true) - $startTime) * 1000);
|
||||||
|
echo "FAILED (" . $e->getMessage() . ", ${elapsed}ms)\n";
|
||||||
|
|
||||||
$stats['failed']++;
|
$stats['failed']++;
|
||||||
$stats['details'][] = [
|
$stats['details'][] = [
|
||||||
'accessnumber' => $accessnumber,
|
'accessnumber' => $accessnumber,
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'error' => $e->getMessage()
|
'error' => $e->getMessage(),
|
||||||
|
'time_ms' => $elapsed
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo str_repeat("-", 60) . "\n";
|
echo str_repeat("-", 60) . "\n";
|
||||||
echo "Complete: " . $stats['success'] . " queued, " . $stats['skipped'] . " skipped, " . $stats['failed'] . " failed\n";
|
echo "Complete: " . $stats['success'] . " queued, " . $stats['failed'] . " failed\n";
|
||||||
|
|
||||||
// Save detailed log
|
// Save detailed log
|
||||||
$logFile = 'batch_pdf_' . date('Ymd_His') . '.log';
|
$logFile = 'batch_pdf_' . date('Ymd_His') . '.log';
|
||||||
$logContent = "Batch PDF Generation Log\n";
|
$logContent = "Batch PDF Generation Log\n";
|
||||||
$logContent .= "Generated: " . date('Y-m-d H:i:s') . "\n";
|
$logContent .= "Generated: " . date('Y-m-d H:i:s') . "\n";
|
||||||
$logContent .= "Input file: $inputFile\n";
|
$logContent .= "Input file: $inputFile\n";
|
||||||
$logContent .= "Total: $total, Success: {$stats['success']}, Skipped: {$stats['skipped']}, Failed: {$stats['failed']}\n";
|
$logContent .= "Endpoint: $baseUrl\n";
|
||||||
|
$logContent .= "Total: $total, Success: {$stats['success']}, Failed: {$stats['failed']}\n";
|
||||||
$logContent .= str_repeat("-", 60) . "\n";
|
$logContent .= str_repeat("-", 60) . "\n";
|
||||||
|
|
||||||
foreach ($stats['details'] as $detail) {
|
foreach ($stats['details'] as $detail) {
|
||||||
$logContent .= $detail['accessnumber'] . " | " . $detail['status'];
|
$logContent .= $detail['accessnumber'] . " | " . $detail['status'];
|
||||||
if (isset($detail['jobId'])) {
|
if (isset($detail['jobId'])) {
|
||||||
$logContent .= " | job: " . $detail['jobId'];
|
$logContent .= " | job: " . $detail['jobId'];
|
||||||
|
$logContent .= " | lang: " . $detail['language'];
|
||||||
}
|
}
|
||||||
if (isset($detail['error'])) {
|
if (isset($detail['error'])) {
|
||||||
$logContent .= " | error: " . $detail['error'];
|
$logContent .= " | error: " . $detail['error'];
|
||||||
}
|
}
|
||||||
$logContent .= "\n";
|
$logContent .= " | " . $detail['time_ms'] . "ms\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
file_put_contents($logFile, $logContent);
|
file_put_contents($logFile, $logContent);
|
||||||
echo "Log saved to: $logFile\n";
|
echo "Log saved to: $logFile\n";
|
||||||
|
|
||||||
exit($stats['failed'] > 0 ? 1 : 0);
|
exit($stats['failed'] > 0 ? 1 : 0);
|
||||||
|
|
||||||
/**
|
|
||||||
* Post HTML to PDF spooler
|
|
||||||
*/
|
|
||||||
function postToSpooler(string $html, string $filename, string $collectionDate = '', string $accessnumber = '', string $hostnumber = ''): string
|
|
||||||
{
|
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL, 'http://glenlis:3000/api/pdf/generate');
|
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
|
||||||
|
|
||||||
$payload = [
|
|
||||||
'html' => $html,
|
|
||||||
'filename' => $filename
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($collectionDate) {
|
|
||||||
$payload['collectionDate'] = $collectionDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($accessnumber) {
|
|
||||||
$payload['accessnumber'] = $accessnumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($hostnumber) {
|
|
||||||
$payload['hostnumber'] = $hostnumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
||||||
'Content-Type: application/json'
|
|
||||||
]);
|
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
|
||||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
$curlError = curl_error($ch);
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
if ($curlError) {
|
|
||||||
throw new \Exception("cURL error: $curlError");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($httpCode !== 200) {
|
|
||||||
throw new \Exception("Spooler API returned HTTP $httpCode");
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = json_decode($response, true);
|
|
||||||
if (!isset($data['jobId'])) {
|
|
||||||
throw new \Exception("Invalid response from spooler: no jobId");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data['jobId'];
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user