211 lines
12 KiB
PHP
Executable File
211 lines
12 KiB
PHP
Executable File
<?php
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 0);
|
|
set_time_limit(0);
|
|
|
|
try {
|
|
$pdo = new PDO('pgsql:host=localhost;dbname=adx_system', 'admin', 'admin123',
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
} catch (PDOException $e) { die("Database connection failed"); }
|
|
|
|
$dataDir = '/opt/PLATFOMRDELIVERABILITYWEVAL';
|
|
$response = ['success' => false, 'message' => '', 'data' => null];
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
header('Content-Type: application/json');
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'scan_files') {
|
|
$files = [];
|
|
if (is_dir($dataDir)) {
|
|
foreach (new DirectoryIterator($dataDir) as $file) {
|
|
if ($file->isDot()) continue;
|
|
$ext = strtolower($file->getExtension());
|
|
if (!in_array($ext, ['csv', 'txt'])) continue;
|
|
$lines = 0;
|
|
$handle = fopen($file->getPathname(), 'r');
|
|
while (!feof($handle)) { fgets($handle); $lines++; }
|
|
fclose($handle);
|
|
$fn = strtolower($file->getBasename());
|
|
$isp = 'Mixed';
|
|
if (strpos($fn,'gmail')!==false) $isp='Gmail';
|
|
elseif (strpos($fn,'hotmail')!==false || strpos($fn,'outlook')!==false) $isp='Hotmail';
|
|
elseif (strpos($fn,'yahoo')!==false) $isp='Yahoo';
|
|
elseif (strpos($fn,'gmx')!==false) $isp='GMX';
|
|
$seg = 'cold';
|
|
if (strpos($fn,'click')!==false) $seg='hot';
|
|
elseif (strpos($fn,'open')!==false || strpos($fn,'active')!==false) $seg='warm';
|
|
$country = null;
|
|
if (preg_match('/[_-](us|uk|ca|de|fr|au|es|nl|se|no|fi)[\._-]/i', $fn, $m)) $country = strtoupper($m[1]);
|
|
$files[] = ['name'=>$file->getBasename(),'size'=>round($file->getSize()/1024,1).'KB','lines'=>$lines-1,'isp'=>$isp,'segment'=>$seg,'country'=>$country];
|
|
}
|
|
}
|
|
usort($files, fn($a,$b) => $b['lines'] - $a['lines']);
|
|
echo json_encode(['success'=>true,'data'=>$files]); exit;
|
|
}
|
|
|
|
if ($action === 'import_file') {
|
|
$file = basename($_POST['file'] ?? '');
|
|
$segment = $_POST['segment'] ?? 'cold';
|
|
$country = $_POST['country'] ?? null;
|
|
$filepath = $dataDir . '/' . $file;
|
|
if (!file_exists($filepath)) { echo json_encode(['success'=>false,'message'=>'File not found']); exit; }
|
|
$handle = fopen($filepath, 'r');
|
|
$first = fgets($handle); rewind($handle);
|
|
$delim = substr_count($first,';') > substr_count($first,',') ? ';' : ',';
|
|
fgetcsv($handle, 0, $delim);
|
|
$imported = 0; $skipped = 0;
|
|
$stmt = $pdo->prepare("INSERT INTO admin.leads (email,country,segment,isp,source_file,created_at) VALUES (?,?,?,?,?,NOW()) ON CONFLICT (email) DO UPDATE SET segment=CASE WHEN EXCLUDED.segment='hot' THEN 'hot' WHEN admin.leads.segment='hot' THEN 'hot' WHEN EXCLUDED.segment='warm' THEN 'warm' ELSE admin.leads.segment END, updated_at=NOW()");
|
|
while (($row = fgetcsv($handle, 0, $delim)) !== false) {
|
|
$email = null;
|
|
foreach ($row as $val) { if (filter_var(trim($val), FILTER_VALIDATE_EMAIL)) { $email = strtolower(trim($val)); break; } }
|
|
if (!$email) { $skipped++; continue; }
|
|
$domain = substr(strrchr($email, "@"), 1);
|
|
$isp = 'Other';
|
|
if (strpos($domain,'gmail')!==false) $isp='Gmail';
|
|
elseif (strpos($domain,'hotmail')!==false || strpos($domain,'outlook')!==false || strpos($domain,'live')!==false) $isp='Hotmail';
|
|
elseif (strpos($domain,'yahoo')!==false) $isp='Yahoo';
|
|
try { $stmt->execute([$email,$country,$segment,$isp,$file]); $imported++; } catch(Exception $e) { $skipped++; }
|
|
}
|
|
fclose($handle);
|
|
echo json_encode(['success'=>true,'message'=>"Imported: $imported, Skipped: $skipped",'data'=>['imported'=>$imported,'skipped'=>$skipped]]); exit;
|
|
}
|
|
}
|
|
|
|
$totalLeads = $pdo->query("SELECT COUNT(*) FROM admin.leads")->fetchColumn() ?: 0;
|
|
$todayImported = $pdo->query("SELECT COUNT(*) FROM admin.leads WHERE created_at::date = CURRENT_DATE")->fetchColumn() ?: 0;
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html><head>
|
|
<meta charset="UTF-8">
|
|
<title>WEVAL SEND Import</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{--primary:#2563eb;--primary-dark:#1d4ed8;--secondary:#7c3aed;--success:#10b981;--warning:#f59e0b;--danger:#ef4444;--bg-dark:#0f172a;--bg-card:#1e293b;--bg-hover:#334155;--text-primary:#f1f5f9;--text-secondary:#94a3b8;--border:#334155}
|
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
body{font-family:'Inter',sans-serif;background:var(--bg-dark);color:var(--text-primary);min-height:100vh}
|
|
.header{background:linear-gradient(135deg,#2563eb 0%,#7c3aed 100%);padding:0 30px;height:70px;display:flex;align-items:center;justify-content:space-between;box-shadow:0 4px 20px rgba(37,99,235,0.3)}
|
|
.logo{display:flex;align-items:center;gap:12px}
|
|
.logo-icon{width:45px;height:45px;background:rgba(255,255,255,0.2);border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:24px}
|
|
.logo-text{font-size:22px;font-weight:700;color:white}
|
|
.header-nav{display:flex;gap:8px}
|
|
.nav-btn{padding:10px 20px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.2);border-radius:10px;color:white;text-decoration:none;font-weight:500;font-size:14px}
|
|
.nav-btn:hover{background:rgba(255,255,255,0.25)}
|
|
.container{max-width:1400px;margin:0 auto;padding:24px}
|
|
.stats-bar{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}
|
|
.stat-card{background:var(--bg-card);border-radius:16px;padding:20px;border:1px solid var(--border);position:relative;overflow:hidden}
|
|
.stat-card::before{content:'';position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,#2563eb,#7c3aed)}
|
|
.stat-value{font-size:32px;font-weight:700;margin-bottom:4px}
|
|
.stat-label{font-size:13px;color:var(--text-secondary)}
|
|
.log-area{background:var(--bg-dark);border:1px solid var(--border);border-radius:10px;padding:16px;font-family:monospace;font-size:12px;max-height:200px;overflow-y:auto}
|
|
.log-success{color:#10b981}
|
|
.log-error{color:#ef4444}
|
|
.log-info{color:#3b82f6}
|
|
.progress-bar{width:100%;height:8px;background:var(--bg-dark);border-radius:4px;overflow:hidden;margin:12px 0}
|
|
.progress-fill{height:100%;background:linear-gradient(90deg,#2563eb,#7c3aed);border-radius:4px;transition:width 0.3s}
|
|
#loading{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(15,23,42,0.9);display:none;justify-content:center;align-items:center;z-index:1000}
|
|
.spinner{width:50px;height:50px;border:4px solid var(--border);border-top-color:var(--primary);border-radius:50%;animation:spin 1s linear infinite}
|
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
.empty-state{text-align:center;padding:60px}
|
|
.empty-icon{font-size:48px;margin-bottom:16px;opacity:0.5}
|
|
.empty-text{color:var(--text-secondary)}
|
|
</style>
|
|
|
|
</head>
|
|
<body>
|
|
<header class="header">
|
|
<div class="logo"><div class="logo-icon">📥</div><div class="logo-text">WEVAL SEND Import</div></div>
|
|
<nav class="header-nav">
|
|
<a href="crm.php" class="nav-btn">👥 CRM</a>
|
|
<a href="world-dashboard.php" class="nav-btn">🌍 Dashboard</a>
|
|
<a href="index.php" class="nav-btn">🏠 WEVAL</a>
|
|
</nav>
|
|
</header>
|
|
<div class="container">
|
|
<div class="stats-bar">
|
|
<div class="stat-card"><div class="stat-value" id="totalFiles">-</div><div class="stat-label">📁 Files Found</div></div>
|
|
<div class="stat-card"><div class="stat-value" id="totalRecords">-</div><div class="stat-label">📧 Total Records</div></div>
|
|
<div class="stat-card"><div class="stat-value"><?php echo number_format($totalLeads); ?></div><div class="stat-label">✅ In Database</div></div>
|
|
<div class="stat-card"><div class="stat-value"><?php echo number_format($todayImported); ?></div><div class="stat-label">📊 Today</div></div>
|
|
</div>
|
|
<div class="panel">
|
|
<div class="panel-header">
|
|
<span class="panel-title">📂 Data Files - /opt/PLATFOMRDELIVERABILITYWEVAL</span>
|
|
<button class="btn btn-secondary" onclick="scanFiles()">🔄 Refresh</button>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="toolbar">
|
|
<input type="text" class="search-input" id="searchBox" placeholder="🔍 Search files...">
|
|
<div class="filter-btns">
|
|
<button class="filter-btn active" data-filter="all">All</button>
|
|
<button class="filter-btn" data-filter="hot">🔥 Hot</button>
|
|
<button class="filter-btn" data-filter="warm">🌡️ Warm</button>
|
|
<button class="filter-btn" data-filter="cold">❄️ Cold</button>
|
|
</div>
|
|
<label style="display:flex;align-items:center;gap:8px;color:var(--text-secondary);font-size:14px"><input type="checkbox" id="selectAll" style="width:18px;height:18px"> Select All</label>
|
|
<button class="btn btn-success" onclick="importSelected()">⬆️ Import Selected</button>
|
|
</div>
|
|
<div class="file-grid" id="fileGrid"><div class="empty-state"><div class="empty-icon">📂</div><p class="empty-text">Loading files...</p></div></div>
|
|
</div>
|
|
</div>
|
|
<div class="panel">
|
|
<div class="panel-header">
|
|
<span class="panel-title">📋 Import Log</span>
|
|
<button class="btn btn-secondary" onclick="clearLog()">Clear</button>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="progress-bar" id="progressBar" style="display:none"><div class="progress-fill" id="progressFill" style="width:0%"></div></div>
|
|
<div class="log-area" id="logArea">Ready to import data...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="loading"><div class="spinner"></div></div>
|
|
function renderFiles(files){
|
|
const grid=document.getElementById('fileGrid');
|
|
if(files.length===0){grid.innerHTML='<div class="empty-state"><div class="empty-icon">📭</div><p class="empty-text">No files found</p></div>';return}
|
|
let html='';
|
|
files.forEach(f=>{
|
|
const segCls=f.segment==='hot'?'badge-hot':f.segment==='warm'?'badge-warm':'badge-cold';
|
|
const segIcon=f.segment==='hot'?'🔥':f.segment==='warm'?'🌡️':'❄️';
|
|
html+=`<div class="file-card">
|
|
<input type="checkbox" class="file-check" data-name="${f.name}" data-segment="${f.segment}" data-country="${f.country||''}">
|
|
<span class="file-name" title="${f.name}">${f.name}</span>
|
|
<span class="file-meta">${f.size}</span>
|
|
<span class="file-meta">${f.lines.toLocaleString()}</span>
|
|
<span class="badge badge-isp">${f.isp}</span>
|
|
<span class="badge ${segCls}">${segIcon} ${f.segment}</span>
|
|
<span class="file-meta">${f.country||'-'}</span>
|
|
</div>`;
|
|
});
|
|
grid.innerHTML=html;
|
|
}
|
|
|
|
async function importSelected(){
|
|
const checked=document.querySelectorAll('.file-check:checked');
|
|
if(checked.length===0){alert('Select files first');return}
|
|
if(!confirm('Import '+checked.length+' file(s)?'))return;
|
|
showLoading();document.getElementById('progressBar').style.display='block';
|
|
let done=0,totalImported=0,totalSkipped=0;
|
|
for(const cb of checked){
|
|
const name=cb.dataset.name,seg=cb.dataset.segment,country=cb.dataset.country;
|
|
log('Importing '+name+'...','info');
|
|
try{
|
|
const r=await fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=import_file&file='+encodeURIComponent(name)+'&segment='+seg+'&country='+country});
|
|
const res=await r.json();
|
|
if(res.success){log('✅ '+name+': '+res.message,'success');totalImported+=res.data.imported;totalSkipped+=res.data.skipped}
|
|
else{log('❌ '+name+': '+res.message,'error')}
|
|
}catch(e){log('❌ '+name+': '+e.message,'error')}
|
|
done++;document.getElementById('progressFill').style.width=(done/checked.length*100)+'%';
|
|
}
|
|
log('📊 Total: '+totalImported+' imported, '+totalSkipped+' skipped','info');
|
|
hideLoading();setTimeout(()=>location.reload(),2000);
|
|
}
|
|
|
|
function log(msg,type='info'){const a=document.getElementById('logArea');a.innerHTML+=`<div class="log-${type}">[${new Date().toLocaleTimeString()}] ${msg}</div>`;a.scrollTop=a.scrollHeight}
|
|
function clearLog(){document.getElementById('logArea').innerHTML='Ready...';document.getElementById('progressBar').style.display='none'}
|
|
function showLoading(){document.getElementById('loading').style.display='flex'}
|
|
function hideLoading(){document.getElementById('loading').style.display='none'}
|
|
</script>
|
|
|
|
</body></html>
|