Site Builder
Editing:
coupon.php
writable 0666
<?php /************************************************************************** * SOCIAL – MULTI‑COUPON CREATOR (save | new | delete | download | upload) *************************************************************************/ declare(strict_types=1); /* ---------- identify profile ---------------------------------------- */ $slug = preg_replace('/[^a-z0-9_]/i', '', $_GET['user'] ?? ''); if ($slug===''){ http_response_code(400); exit; } $root = $_SERVER['DOCUMENT_ROOT']; $dir = "$root/social/$slug"; $paid = is_file("$dir/social.json"); if(!$paid && !is_file("$dir/new-social.json")){ http_response_code(404); exit; } $cpFile = "$dir/coupon.json"; /* ---------- helpers -------------------------------------------------- */ function normalise(array $a):array{ foreach($a as&$c){ $c=[ 'title' =>$c['title'] ?? '', 'desc' =>$c['desc'] ?? ($c['description']??''), 'code' =>$c['code'] ?? '', 'link' =>$c['link'] ?? '', 'expiry' =>$c['expiry'] ?? ($c['expires']??''), 'active' =>$c['active'] ?? true ]; } return $a; } function loadCoupons(string $f):array{ if(!is_file($f)) return []; $j=json_decode(file_get_contents($f),true,512,JSON_THROW_ON_ERROR); if(array_is_list($j)) return normalise($j); $a=[]; foreach($j as $k=>$v) if(is_numeric($k)) $a[(int)$k]=$v; if(!$a) $a[]=$j; ksort($a); return normalise(array_values($a)); } function saveCoupons(string $f,array $a):void{ file_put_contents($f,json_encode($a,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES),LOCK_EX); } function esc($s){return htmlspecialchars($s,ENT_QUOTES,'UTF-8');} /* ---------- download ------------------------------------------------- */ if(isset($_GET['download']) && $paid){ header('Content-Type: application/json'); header('Content-Disposition: attachment; filename="'.rawurlencode($slug).'-coupons.json"'); echo json_encode(loadCoupons($cpFile),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); exit; } /* ---------- AJAX endpoints ------------------------------------------ */ if(isset($_GET['fetch'])){ echo json_encode(['success'=>true,'coupons'=>loadCoupons($cpFile)]); exit; } if($_SERVER['REQUEST_METHOD']==='POST' && $paid){ $in = json_decode(file_get_contents('php://input'),true); $act= $in['action']??'save'; $idx= intval($in['index']??0); $arr= loadCoupons($cpFile); if($act==='upload'){ $raw=$in['blob']??''; $test=json_decode($raw,true); if(!is_array($test)){echo json_encode(['success'=>false]);exit;} $arr=normalise(array_values($test)); saveCoupons($cpFile,$arr); echo json_encode(['success'=>true]); exit; } if($act==='delete'){ if(isset($arr[$idx])){array_splice($arr,$idx,1);saveCoupons($cpFile,$arr);} echo json_encode(['success'=>true,'index'=>0]); exit; } /* save / new */ $new=[ 'title'=>trim($in['title']??''),'desc'=>trim($in['desc']??''), 'code'=>trim($in['code']??''),'link'=>trim($in['link']??''), 'expiry'=>trim($in['expiry']??''),'active'=>true ]; foreach($arr as $k=>$c) if(strcasecmp($c['title'],$new['title'])===0 && ($act==='new'||$k!==$idx)) {echo json_encode(['success'=>false,'msg'=>'Duplicate title']);exit;} if($act==='new'){ $arr[]=$new; $idx=array_key_last($arr);} else $arr[$idx]=$new; saveCoupons($cpFile,$arr); echo json_encode(['success'=>true,'index'=>$idx]); exit; } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Coupons – @<?=esc($slug)?></title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> :root{--bg:#f6f8fb;--accent:#2357d7;--accent-dk:#0f47c6;--gold:#ef8f13;--danger:#c00} body{margin:0;font-family:system-ui,Arial,sans-serif;background:var(--bg);color:#234} .top{background:#eee;padding:.8em 1.2em;font-weight:900} h1{font-size:1.45rem;margin:0} /* inputs */ input,textarea,select{width:100%;padding:.5rem;font-size:1rem;border:1px solid #b7c2df;border-radius:7px} label{font-weight:600;display:block;margin:.7rem 0 .3rem} button{padding:.55rem 1.2rem;font-size:1rem;border:0;border-radius:8px;cursor:pointer;font-weight:700} /* buttons */ .primary{background:var(--gold);color:#fff}.primary:hover{background:#d97706} .alt{background:#aac8ff;color:#103e9d}.alt:hover{background:#8ab4ff} .delete{background:#ffe4e4;color:var(--danger);padding:.4rem .85rem;font-size:1rem;border-radius:6px}.delete:hover{background:#ffcccc} .badge{display:inline-block;padding:.35rem .75rem;border-radius:12px;font-size:.78rem;font-weight:700;color:#fff;background:#2e7d32} /* selector row */ #selectWrap{margin:1.2rem 0} #selectWrap label{margin-bottom:.4rem} /* allow label to wrap above select on phone */ #selectWrap select{width:100%;max-width:480px} /* form */ .form-card{background:#fffbe6;border:2px solid #ffd973;padding:2rem;border-radius:18px;box-shadow:0 4px 20px #f5db9c3c} .btn-row{display:flex;gap:1rem;flex-wrap:wrap;margin-top:1.2rem} .btn-row .delete{margin-left:auto} /* preview */ .preview{background:#fff;border:3px solid #ffb63b;border-radius:26px;padding:2rem;max-width:500px;margin:auto;box-shadow:0 8px 28px #c59e6933} .preview h2{margin:.15rem 0 .55rem;color:#df6200;font-size:1.4rem} .preview .code{display:inline-block;padding:.35rem 2rem;border:2px dashed #ffbe4e;border-radius:9px;font-weight:700;background:#ffefc1;color:#a95600;font-family:monospace} .desc{color:#56411e;margin-bottom:1.1rem;line-height:1.45} .desc.collapsed{max-height:4.6rem;overflow:hidden;position:relative} .desc.collapsed:after{content:'';position:absolute;right:0;bottom:0;width:90%;height:1.9rem;background:linear-gradient(to top,#fff 0%,rgba(255,255,255,0) 100%)} .read-more{color:#b0640d;text-decoration:underline;cursor:pointer;font-weight:600} .get-btn{display:inline-block;margin:.9rem 0 0;background:var(--accent);color:#fff;padding:.55rem 1.6rem;border-radius:8px;font-weight:700;text-decoration:none} .get-btn:hover{background:var(--accent-dk)} .toolrow{display:flex;justify-content:flex-end;gap:.9rem;margin-bottom:.6rem} .btn-mini{background:#ffeebb;box-shadow:0 1px 5px #ffeebb50}.btn-mini:hover{background:#ffd670;color:#fff} /* backup / restore */ .backup{margin:2.5rem auto 0;max-width:500px;text-align:center} .notice{margin-top:.8rem;font-weight:600} .notice.ok{color:#0a7b38}.notice.err{color:var(--danger)} .container{max-width:760px;margin:2rem auto;padding:0 1rem} </style> </head> <script src="/geo/geofence-guard.js" defer></script> <body> <div class="top"><a href="/" style="text-decoration:none;color:#2a3ca5">BestDealOn</a> » Coupon Builder</div> <div class="container"> <div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:.8rem"> <h1>Coupon Creator for @<?=esc($slug)?></h1><span class="badge">verified creator</span> </div> <!-- selector --> <div id="selectWrap"> <label>Select coupon to edit <select id="couponSelect"></select> </label> </div> <!-- form --> <form id="couponForm" class="form-card" autocomplete="off"> <input type="hidden" name="index" value="0"> <label>Coupon Headline / Title <input name="title" maxlength="100" required></label> <label>Details / Description <textarea name="desc" rows="4" required></textarea></label> <label>Coupon Code <input name="code" maxlength="40" required></label> <label>Referral / Deal Link <input name="link" placeholder="https://example.com/deal"></label> <label>Expires <input type="date" name="expiry" id="expiryField"></label> <div class="btn-row"> <button class="primary" type="submit" id="saveBtn" data-act="save">Save changes</button> <button class="alt" type="submit" id="newBtn" data-act="new" style="display:none">Save as new</button> <button id="deleteBtn" class="delete" type="button" title="Delete selected coupon">✖</button> </div> <div id="saveMsg" style="margin-top:.9rem;font-weight:600"></div> </form> <!-- preview --> <div style="margin-top:2.4rem"> <div class="toolrow"> <button class="btn-mini" id="printBtn">🖨️ Print</button> <button class="btn-mini" id="shareBtn">📤 Share</button> </div> <div class="preview" id="preview"> <h2 id="pvTitle">Your Coupon Headline Here</h2> <div class="desc collapsed" id="pvDesc"></div><span id="readMore" class="read-more" style="display:none">read more</span> <div style="display:flex;gap:.6rem;margin:.8rem 0"><strong>Coupon Code:</strong><span class="code" id="pvCode">BESTDEAL</span></div> <a id="pvLink" class="get-btn" style="display:none" target="_blank" rel="noopener">Get Deal Now »</a> <p style="margin-top:1rem"><strong>Expires:</strong> <span id="pvExp">No Expiry</span></p> </div> </div> <!-- back‑up / restore --> <div class="backup"> <a href="coupon.php?user=<?=esc($slug)?>&download=1" class="btn-mini" style="text-decoration:none;padding:.55rem 1.3rem">📥 Download JSON</a> <div style="margin-top:1rem"> <label style="font-weight:600">Restore from file (.json): <input type="file" id="uploadInput" accept=".json,application/json"> </label> </div> <div id="notice" class="notice"></div> </div> </div> <script> const slug=<?=json_encode($slug)?>; let coupons=[], cur=0; const $=q=>document.querySelector(q); /* ---------- load & selector --------------- */ async function load(){ coupons=(await fetch(`coupon.php?user=${slug}&fetch=1`).then(r=>r.json())).coupons||[]; if(!coupons.length) coupons=[{title:'',desc:'',code:'',link:'',expiry:''}]; const sel=$('#couponSelect'); sel.innerHTML=''; coupons.forEach((c,i)=>{const o=document.createElement('option');o.value=i;o.textContent=c.title||`Coupon ${i+1}`;sel.appendChild(o);}); $('#selectWrap').style.display=coupons.length?'block':'none'; select(0); } $('#couponSelect').onchange=e=>select(+e.target.value); function select(i){cur=i; $('[name=index]').value=i; const c=coupons[i]; ['title','desc','code','link','expiry'].forEach(k=>$(`[name=${k}]`).value=c[k]||''); preview();} /* ---------- preview ------------------------ */ function preview(){ const g=n=>$(`[name=${n}]`).value.trim(); $('#pvTitle').textContent=g('title')||'Your Coupon Headline Here'; $('#pvCode').textContent=g('code')||'BESTDEAL'; $('#pvExp').textContent=g('expiry')||'No Expiry'; const desc=g('desc'), pvD=$('#pvDesc'), rm=$('#readMore'), LIM=170; if(desc.length>LIM){pvD.textContent=desc.slice(0,LIM)+'…';pvD.classList.add('collapsed');rm.style.display=''; rm.onclick=()=>{pvD.textContent=desc;pvD.classList.remove('collapsed');rm.style.display='none';};} else{pvD.textContent=desc||'Your best deal description will appear here.';pvD.classList.remove('collapsed');rm.style.display='none';} const link=g('link'); if(link){$('#pvLink').href=link.startsWith('http')?link:`https://${link}`;$('#pvLink').style.display='inline-block';} else $('#pvLink').style.display='none'; const dup=coupons.some((c,i)=>i!==cur&&c.title.toLowerCase()===g('title').toLowerCase()); $('#newBtn').style.display=g('title')&&!dup&&g('title')!==coupons[cur].title?'inline-block':'none'; } document.querySelectorAll('.form-card input,.form-card textarea').forEach(el=>el.oninput=preview); /* ---------- save / new --------------------- */ $('#couponForm').onsubmit=async e=>{ e.preventDefault(); const btn=document.activeElement.closest('button[data-act]')||$('#saveBtn'); const fd=new FormData(e.target), data={action:btn.dataset.act}; fd.forEach((v,k)=>data[k]=v); const j=await fetch(`coupon.php?user=${slug}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)}).then(r=>r.json()); $('#saveMsg').textContent=j.success?'Saved!':(j.msg||'Error'); if(j.success){await load(); $('#couponSelect').value=j.index; select(j.index);} }; /* ---------- delete ------------------------- */ $('#deleteBtn').onclick=async()=>{ if(!coupons.length) return; if(!confirm('Delete this coupon? This cannot be undone.')) return; await fetch(`coupon.php?user=${slug}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'delete',index:cur})}); await load(); $('#saveMsg').textContent='Deleted.'; }; /* ---------- upload ------------------------- */ $('#uploadInput').onchange=async e=>{ const f=e.target.files[0]; if(!f) return; const txt=await f.text(); try{ JSON.parse(txt); const ok=(await fetch(`coupon.php?user=${slug}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'upload',blob:txt})}).then(r=>r.json())).success; $('#notice').textContent=ok?'Imported!':'Upload failed'; $('#notice').className='notice '+(ok?'ok':'err'); if(ok) await load(); }catch{ $('#notice').textContent='Invalid JSON'; $('#notice').className='notice err'; } }; /* ---------- print / share ------------------ */ $('#printBtn').onclick=()=>{const w=open('','','width=650,height=800');w.document.write(`<html><head><title>Print</title><style>${document.querySelector('style').innerHTML}</style></head><body>${$('#preview').outerHTML}</body></html>`);w.document.close();setTimeout(()=>{w.print();w.close();},250);}; $('#shareBtn').onclick=async e=>{const url=location.href;try{if(navigator.share)await navigator.share({title:'My Best Deal',url});else await navigator.clipboard.writeText(url);e.target.textContent='✅ Copied!';setTimeout(()=>e.target.textContent='📤 Share',1600);}catch{}}; load(); </script> </body> </html>
Save changes
Create folder
writable 0777
Create
Cancel