Files
2026-09-11 18:06:17 +07:00

36 lines
1.8 KiB
PHP

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class AuditService
{
private $CI;
public function __construct() { $this->CI =& get_instance(); }
public function record($module, $entityType, $entityId, $action, $before = null, $after = null, $userId = null)
{
$previous = $this->CI->db->select('record_hash')->order_by('id','DESC')->limit(1)->get('immutable_audit_logs')->row();
$created = date('Y-m-d H:i:s');
$data = array(
'module'=>(string)$module, 'entity_type'=>(string)$entityType, 'entity_id'=>(string)$entityId,
'action'=>(string)$action, 'before_data'=>$this->encode($before), 'after_data'=>$this->encode($after),
'user_id'=>$userId ? (int)$userId : null,
'ip_address'=>isset($this->CI->input) ? $this->CI->input->ip_address() : null,
'user_agent'=>isset($this->CI->input) ? substr((string)$this->CI->input->user_agent(),0,255) : null,
'request_id'=>app_env('HTTP_X_REQUEST_ID', null) ?: null,
'previous_hash'=>$previous ? $previous->record_hash : null, 'created_at'=>$created
);
$data['record_hash'] = hash('sha256', ($data['previous_hash'] ?: '') . json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
if (!$this->CI->db->insert('immutable_audit_logs', $data)) throw new RuntimeException('Gagal menulis audit trail.');
return (int)$this->CI->db->insert_id();
}
private function encode($value)
{
if ($value === null) return null;
$value = json_decode(json_encode($value), true);
$walk = function (&$item, $key) { if (preg_match('/password|token|secret|authorization/i', (string)$key)) $item = '[REDACTED]'; };
array_walk_recursive($value, $walk);
return json_encode($value, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
}
}