|
Server : Apache/2.4.18 (Ubuntu) System : Linux canvaswebdesign 3.13.0-71-generic #114-Ubuntu SMP Tue Dec 1 02:34:22 UTC 2015 x86_64 User : oppastar ( 1041) PHP Version : 7.0.33-0ubuntu0.16.04.15 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, Directory : /var/www/laciasmara.com/public_html/shop/application/helpers/ |
Upload File : |
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
* Visit Tracking Helper
* Helper untuk tracking visits dengan support affiliate referral
*
* Usage in controller:
* $this->load->helper('visit');
* track_visit(); // Will automatically track current page visit
*/
if (!function_exists('track_visit')) {
/**
* Track page visit dengan support untuk affiliate referral
*
* @param array $custom_data Optional custom data untuk override
* @return int|false Visit ID atau false jika gagal
*/
function track_visit($custom_data = [])
{
$CI = &get_instance();
$CI->load->database();
// Prevent duplicate tracking dalam satu request
static $already_tracked = false;
if ($already_tracked) {
return false;
}
// Get visitor information
$ip_address = $CI->input->ip_address();
$user_agent = $CI->input->user_agent();
$current_url = current_url() . ($_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '');
$referrer_url = $CI->input->server('HTTP_REFERER');
// Parse referrer domain
$referrer_domain = null;
if ($referrer_url) {
$parsed = parse_url($referrer_url);
$referrer_domain = isset($parsed['host']) ? $parsed['host'] : null;
}
// Get or create session ID for unique visitor tracking
$session_id = _get_or_create_session_id();
// Detect page type
$page_type = _detect_page_type();
// Get product ID if on product page
$product_id = _get_product_id_from_url();
// Parse UTM parameters
$utm_params = _parse_utm_parameters();
// Check for affiliate referral code
$affiliate_data = _check_affiliate_referral();
// Check untuk duplicate dalam timeframe singkat (prevent double-click)
$recent_visit = $CI->db
->select('id')
->from('visits')
->where('session_id', $session_id)
->where('url', substr($current_url, 0, 500))
->where('created_at >', date('Y-m-d H:i:s', strtotime('-10 seconds')))
->limit(1)
->get()
->row();
if ($recent_visit) {
$already_tracked = true;
return $recent_visit->id;
}
// Prepare visit data
$visit_data = array_merge([
'ip_address' => $ip_address,
'session_id' => $session_id,
'user_agent' => substr($user_agent, 0, 500), // Limit length
'url' => substr($current_url, 0, 500),
'page_type' => $page_type,
'product_id' => $product_id,
'referrer_url' => $referrer_url ? substr($referrer_url, 0, 500) : null,
'referrer_domain' => $referrer_domain,
'is_affiliate_visit' => $affiliate_data['is_affiliate'] ? 1 : 0,
'affiliator_id' => $affiliate_data['affiliator_id'],
'referral_code' => $affiliate_data['referral_code'],
'link_id' => $affiliate_data['link_id'],
'utm_source' => $utm_params['utm_source'],
'utm_medium' => $utm_params['utm_medium'],
'utm_campaign' => $utm_params['utm_campaign'],
'utm_term' => $utm_params['utm_term'],
'utm_content' => $utm_params['utm_content'],
'converted_to_order' => 0,
'created_at' => date('Y-m-d H:i:s')
], $custom_data);
// Insert to database
$CI->db->insert('visits', $visit_data);
$visit_id = $CI->db->insert_id();
// Mark as tracked
$already_tracked = true;
// Update link statistics if affiliate visit
if ($affiliate_data['link_id']) {
_update_link_statistics($affiliate_data['link_id'], $session_id, $visit_id);
}
// Store affiliate info in session for order tracking
if ($affiliate_data['is_affiliate']) {
_store_affiliate_session($affiliate_data, $visit_id);
}
return $visit_id;
}
}
if (!function_exists('mark_visit_converted')) {
/**
* Mark visit as converted to order
* Call this setelah order berhasil dibuat
*
* @param int $order_id
* @param int $visit_id Optional, jika null akan ambil dari session
* @return bool
*/
function mark_visit_converted($order_id, $visit_id = null)
{
$CI = &get_instance();
$CI->load->database();
if (!$visit_id) {
$visit_id = $CI->session->userdata('current_visit_id');
}
if (!$visit_id) {
return false;
}
$update_data = [
'converted_to_order' => 1,
'order_id' => $order_id,
'converted_at' => date('Y-m-d H:i:s')
];
$CI->db->where('id', $visit_id);
return $CI->db->update('visits', $update_data);
}
}
if (!function_exists('get_affiliate_from_session')) {
/**
* Get affiliate data from session
* Digunakan saat membuat commission record
*
* @return array|null
*/
function get_affiliate_from_session()
{
$CI = &get_instance();
$affiliate_data = $CI->session->userdata('affiliate_tracking');
if (!$affiliate_data) {
return null;
}
// Check if still valid (24 hours)
$stored_time = isset($affiliate_data['stored_at']) ? $affiliate_data['stored_at'] : 0;
$current_time = time();
if (($current_time - $stored_time) > 86400) { // 24 hours
// Expired, remove from session
$CI->session->unset_userdata('affiliate_tracking');
return null;
}
return $affiliate_data;
}
}
// ============================================================================
// PRIVATE HELPER FUNCTIONS
// ============================================================================
if (!function_exists('_get_or_create_session_id')) {
/**
* Get atau create unique session ID untuk visitor
*/
function _get_or_create_session_id()
{
$CI = &get_instance();
$session_id = $CI->session->userdata('visitor_session_id');
if (!$session_id) {
// Generate unique session ID
$session_id = md5(uniqid(rand(), true));
$CI->session->set_userdata('visitor_session_id', $session_id);
}
return $session_id;
}
}
if (!function_exists('_detect_page_type')) {
/**
* Detect page type berdasarkan URI
*/
function _detect_page_type()
{
$CI = &get_instance();
$segment1 = $CI->uri->segment(1);
$segment2 = $CI->uri->segment(2);
// Home page
if (!$segment1 || $segment1 === 'home') {
return 'home';
}
// Shop/Product pages
if ($segment1 === 'shop') {
if ($segment2 === 'product' || $segment2 === 'productdetail') {
return 'product';
}
return 'shop';
}
// Cart page
if ($segment1 === 'cart' || $segment1 === 'keranjang') {
return 'cart';
}
// Checkout page
if ($segment1 === 'checkout' || $segment1 === 'shipping') {
return 'checkout';
}
return 'other';
}
}
if (!function_exists('_get_product_id_from_url')) {
/**
* Extract product ID dari URL jika ada
*/
function _get_product_id_from_url()
{
$CI = &get_instance();
$segment1 = $CI->uri->segment(1);
$segment2 = $CI->uri->segment(2);
// Check if product page
if ($segment1 === 'shop' && ($segment2 === 'product')) {
$segment3 = $CI->uri->segment(3);
if ($segment3) {
// Query product by slug
$product = $CI->db
->select('id_products as id')
->from('products')
->where('alias', $segment3)
->get()
->row();
if ($product) {
return $product->id;
}
}
}
return null;
}
}
if (!function_exists('_parse_utm_parameters')) {
/**
* Parse UTM parameters dari URL
*/
function _parse_utm_parameters()
{
$CI = &get_instance();
return [
'utm_source' => $CI->input->get('utm_source'),
'utm_medium' => $CI->input->get('utm_medium'),
'utm_campaign' => $CI->input->get('utm_campaign'),
'utm_term' => $CI->input->get('utm_term'),
'utm_content' => $CI->input->get('utm_content')
];
}
}
if (!function_exists('_check_affiliate_referral')) {
/**
* Check apakah visit ini dari affiliate referral
* Matching berdasarkan referral_code + full URL comparison
*/
function _check_affiliate_referral()
{
$CI = &get_instance();
$result = [
'is_affiliate' => false,
'affiliator_id' => null,
'referral_code' => null,
'link_id' => null
];
// Check for 'ref' parameter
$ref_code = $CI->input->get('ref');
if (!$ref_code) {
return $result;
}
// Query affiliator by referral code
$affiliator = $CI->db
->select('id, referral_code, status')
->from('affiliators')
->where('referral_code', strtoupper($ref_code))
->where('status', 'active')
->get()
->row();
if (!$affiliator) {
return $result;
}
$result['is_affiliate'] = true;
$result['affiliator_id'] = $affiliator->id;
$result['referral_code'] = $affiliator->referral_code;
// Build current complete URL (with query string)
$current_url = current_url();
$query_string = $_SERVER['QUERY_STRING'];
$current_full_url = $current_url . ($query_string ? '?' . $query_string : '');
// Normalize URL for comparison
$current_normalized = _normalize_url_for_comparison($current_full_url);
// Get all active links for this affiliator
// Priority: specific links (brand, product, category) first, then general
$links = $CI->db
->select('id, full_url, link_type')
->from('affiliator_links')
->where('affiliator_id', $affiliator->id)
->where('status', 'active')
->where('(expires_at IS NULL OR expires_at > NOW())')
->order_by("link_type = 'general'", 'ASC') // Specific links first
->order_by('CHAR_LENGTH(full_url)', 'DESC') // Longer URLs first
->get()
->result();
$matched_link = null;
foreach ($links as $link) {
$link_normalized = _normalize_url_for_comparison($link->full_url);
// Exact match
if ($current_normalized === $link_normalized) {
$matched_link = $link;
break;
}
}
// Fallback: if no exact match, use general link
if (!$matched_link) {
foreach ($links as $link) {
if ($link->link_type === 'general') {
$matched_link = $link;
break;
}
}
}
if ($matched_link) {
$result['link_id'] = $matched_link->id;
}
return $result;
}
}
if (!function_exists('_normalize_url_for_comparison')) {
/**
* Normalize URL untuk comparison
* Handle trailing slash, case sensitivity, query parameter order
*/
function _normalize_url_for_comparison($url)
{
// Parse URL
$parsed = parse_url(strtolower($url));
// Get path and query
$path = isset($parsed['path']) ? $parsed['path'] : '';
$query = isset($parsed['query']) ? $parsed['query'] : '';
// Normalize path: remove all leading/trailing slashes
$path = '/' . trim($path, '/');
// If path is just "/", keep it as empty
if ($path === '/') {
$path = '';
}
// Parse query string and sort parameters for consistent comparison
parse_str($query, $params);
ksort($params);
$normalized_query = http_build_query($params);
// Build normalized URL
$normalized = $path . ($normalized_query ? '?' . $normalized_query : '');
return $normalized;
}
}
if (!function_exists('_update_link_statistics')) {
/**
* Update statistics untuk affiliate link
* @param int $link_id ID dari affiliate link
* @param string $session_id Session ID visitor
* @param int $current_visit_id ID visit yang baru diinsert (untuk di-exclude)
*/
function _update_link_statistics($link_id, $session_id, $current_visit_id = null)
{
$CI = &get_instance();
$ip_address = $CI->input->ip_address();
// Update total clicks
$CI->db->set('total_clicks', 'total_clicks + 1', FALSE);
$CI->db->set('last_clicked_at', date('Y-m-d H:i:s'));
$CI->db->where('id', $link_id);
$CI->db->update('affiliator_links');
// Check if this IP has clicked this link before (exclude current visit)
$query = $CI->db
->select('id')
->from('visits')
->where('link_id', $link_id)
->where('ip_address', $ip_address);
// Exclude current visit ID
if ($current_visit_id) {
$query->where('id !=', $current_visit_id);
}
$existing_ip_visit = $query->limit(1)->get()->row();
// Only increment unique_clicks if this is the first time from this IP
if (!$existing_ip_visit) {
$CI->db->set('unique_clicks', 'unique_clicks + 1', FALSE);
$CI->db->where('id', $link_id);
$CI->db->update('affiliator_links');
}
}
}
if (!function_exists('_store_affiliate_session')) {
/**
* Store affiliate information di session
* Untuk tracking conversion nanti
*/
function _store_affiliate_session($affiliate_data, $visit_id)
{
$CI = &get_instance();
$session_data = [
'affiliator_id' => $affiliate_data['affiliator_id'],
'referral_code' => $affiliate_data['referral_code'],
'link_id' => $affiliate_data['link_id'],
'visit_id' => $visit_id,
'stored_at' => time()
];
$CI->session->set_userdata('affiliate_tracking', $session_data);
$CI->session->set_userdata('current_visit_id', $visit_id);
}
}