Site Builder
Editing:
tools-writing-blogs1.php
writable 0666
<?php /***************************************************************** * RF Safe – Single‑Prompt Article Generator (v1.8, toolbox edition) * ---------------------------------------------------------------- * • Shares the same encrypted cookie (‘openai_key’) with all AI tools * • Compact header toolbar instead of sidebar; fully mobile‑friendly *****************************************************************/ /* ---------- 1. Constants & encryption helpers ----------------- */ const COOKIE_NAME = 'openai_key'; const COOKIE_TTL = 30 * 24 * 3600; // 30 days const SECRET = __FILE__; // file‑specific pepper /* derive “root” for cross‑sub‑domain cookie */ $host = $_SERVER['HTTP_HOST'] ?? ''; $cookieDomain = (preg_match('/([a-z0-9-]+\.[a-z]{2,})$/i', $host, $m) && !filter_var($host, FILTER_VALIDATE_IP)) ? '.'.$m[1] : ''; // ‘’ when localhost / raw IP function enc(string $plain): string { $m = 'aes-128-ctr'; $k = substr(hash('sha256', SECRET, true), 0, 16); $iv= random_bytes(openssl_cipher_iv_length($m)); return base64_encode(openssl_encrypt($plain, $m, $k, 0, $iv).'::'.$iv); } function dec(string $cipher): string { [$ct,$iv] = explode('::', base64_decode($cipher), 2) + [null,null]; if(!$ct||!$iv) return ''; $m='aes-128-ctr'; $k=substr(hash('sha256', SECRET, true), 0, 16); return openssl_decrypt($ct,$m,$k,0,$iv) ?: ''; } /* ---------- 2. Save / delete API key -------------------------- */ $msg=''; if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['save_key'])) { $raw = trim($_POST['api_key']); $ctx = stream_context_create(['http'=>[ 'method'=>'GET','header'=>"Authorization: Bearer $raw\r\n",'timeout'=>8 ]]); if (@file_get_contents('https://api.openai.com/v1/models', false, $ctx)) { setcookie(COOKIE_NAME, enc($raw), time()+COOKIE_TTL, '/', $cookieDomain, isset($_SERVER['HTTPS']), true); header('Location: '.$_SERVER['REQUEST_URI']); exit; } $msg='❌ Invalid key'; } if (isset($_GET['logout'])) { setcookie(COOKIE_NAME,'',time()-3600,'/',$cookieDomain,isset($_SERVER['HTTPS']),true); header('Location: '.$_SERVER['PHP_SELF']); exit; } /* ---------- 3. Sticky form defaults --------------------------- */ $topic=$keywords=$linkurl=''; $sections=$paras=3; $lang='English'; $style='Creative'; $tone='Neutral'; $points=[]; $models=['gpt-3.5-turbo','gpt-4o-mini','gpt-4']; $model = in_array($_REQUEST['model']??'', $models, true) ? $_REQUEST['model'] : 'gpt-4o-mini'; $html =''; /* ---------- 4. Generate (if requested) ------------------------ */ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['generate'])) { /* grab inputs */ $topic = trim($_POST['topic'] ?? ''); $keywords = trim($_POST['keywords'] ?? ''); $linkurl = trim($_POST['linkurl'] ?? ''); $sections = max(1,intval($_POST['sections']??3)); $paras = max(1,intval($_POST['paras']??3)); $lang = $_POST['lang'] ?? 'English'; $style = $_POST['style'] ?? 'Creative'; $tone = $_POST['tone'] ?? 'Neutral'; $model = in_array($_POST['model']??'', $models, true) ? $_POST['model'] : $model; $points = array_filter(array_map('trim', $_POST['points']??[])); $key = isset($_COOKIE[COOKIE_NAME]) ? dec($_COOKIE[COOKIE_NAME]) : ''; if(!$key){ $msg='❌ Missing API key.'; } elseif($topic===''){ $msg='❌ Topic required.'; } else { /* build prompt */ $kwText = $keywords ? " Include keywords: $keywords." : ''; $linkText = ($keywords && $linkurl) ? " Hyperlink each keyword to $linkurl." : ''; $pointsText = $points ? ' Cover: '.implode('; ', $points).'.' : ''; $prompt = "Write a $lang $style article in a $tone tone about «$topic». ". "Use $sections sections (each <h2>) and $paras paragraph".($paras>1?'s':'').' per section. '. "Use <h3> where helpful.".$kwText.$linkText.$pointsText. ' Append <p class="excerpt">Excerpt: …</p>. Output ONLY HTML.'; /* OpenAI call */ $payload=['model'=>$model,'messages'=>[['role'=>'user','content'=>$prompt]], 'max_tokens'=>max(800,$sections*$paras*200),'temperature'=>0.7]; $ch=curl_init('https://api.openai.com/v1/chat/completions'); curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>1, CURLOPT_HTTPHEADER=>['Authorization: Bearer '.$key,'Content-Type: application/json'], CURLOPT_POST=>1,CURLOPT_POSTFIELDS=>json_encode($payload),CURLOPT_TIMEOUT=>50]); $resp=curl_exec($ch); curl_close($ch); $html = json_decode($resp,true)['choices'][0]['message']['content'] ?? '❌ No content.'; } } /* ---------- 5. Option lists (unchanged) ----------------------- */ $langs = ['English','Spanish','German','French','Italian','Portuguese','Dutch']; $styles= ['Creative','Informative','Narrative','Persuasive','Analytical','Journalistic']; $tones = ['Neutral','Cheerful','Humorous','Assertive','Inspirational','Professional','Emotional']; /* ---------- 6. Page ------------------------------------------------------ */ ?> <!doctype html><html lang="en"><head> <meta charset="utf-8"><title>Promptinator • Article Generator</title> <meta name=viewport content="width=device-width,initial-scale=1"> <link rel=stylesheet href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> <style> :root{--brand:#0f3760;--blue:#0066ff;--blue-d:#0250e0;--grey-bg:#f1f4fb} body{background:var(--grey-bg);margin:0;font-family:system-ui,Roboto,Arial,sans-serif} header{background:#eee;padding:.8rem 1.2rem;font-weight:700;display:flex;align-items:center;justify-content:space-between} header nav a{color:var(--brand);text-decoration:none;margin-right:.4rem} header nav a:last-child{margin:0} .container{max-width:920px;margin:2rem auto;padding:0 1rem} form.grid{display:grid;gap:1.2rem} .toolbar{display:flex;gap:1rem;align-items:center;flex-wrap:wrap;margin-bottom:1.4rem} .toolbar input{padding:.5rem .75rem;border:1px solid #ccd3e5;border-radius:6px;width:260px;max-width:100%} .toolbar select{padding:.5rem;border-radius:6px} .badge{display:flex;align-items:center;gap:.3ch;font-size:.9rem} .badge.green{color:#0abf5b} .badge.red{color:#c43} .badge button{border:none;background:none;color:inherit;font-size:1rem;cursor:pointer} button.primary{background:var(--blue);color:#fff;border:none;border-radius:6px;padding:.6rem 1.3rem;font-weight:600;cursor:pointer} button.primary:hover{background:var(--blue-d)} .copyBtn{margin-top:.6rem} textarea{font-family:"Fira Code",monospace} .preview{background:#fff;border:1px solid #e2e6f0;border-radius:8px;padding:1rem;max-height:60vh;overflow:auto} @media(max-width:600px){.toolbar{flex-direction:column;align-items:flex-start}.toolbar input{width:100%}} </style></head><body> <!-- ─── breadcrumb header identical to other tools ─── --> <header> <nav> <a href="/">BestDealOn</a> » <a href="/members/dashboard.php">Dashboard</a> » <a href="/ai-tools/tools.php">AI Toolbox</a> » Article Generator </nav> <a href="/<?=$_SESSION['slug']??''?>" style="text-decoration:none">View Site</a> </header> <div class="container"> <!-- ───────── Top toolbar ───────── --> <?php $keySaved = isset($_COOKIE[COOKIE_NAME]) && dec($_COOKIE[COOKIE_NAME]); ?> <div class="toolbar"> <?php if(!$keySaved): ?> <form method="post" style="display:flex;gap:.6rem;flex-wrap:wrap"> <input type="password" name="api_key" placeholder="Enter OpenAI key…" required> <button class="primary" name="save_key">Save Key</button> <?= $msg ? "<span class='badge red'>$msg</span>" : '' ?> </form> <?php else: ?> <span class="badge green">● API key saved <button title="Delete key" onclick="location='?logout=1'">❌</button> </span> <form method="get"> <select name="model" onchange="this.form.submit()"> <?php foreach($models as $m):?><option value="<?=$m?>" <?=$m===$model?'selected':''?>><?=$m?></option><?php endforeach;?> </select> </form> <?php endif; ?> </div> <!-- ───────── Generator form ───────── --> <?php if($keySaved): ?> <form method="post" class="grid" id="mainForm"> <input type="hidden" name="model" value="<?=htmlspecialchars($model)?>"> <label>Topic <div style="position:relative"> <input name="topic" id="topic" placeholder="e.g. Electric bicycles" value="<?=htmlspecialchars($topic)?>" required> <button type="button" id="micBtn" aria-label="Speak" style="position:absolute;right:.5rem;top:50%;transform:translateY(-50%);border:none;background:none;font-size:1.2rem;cursor:pointer">🎤</button> </div> </label> <label>Keywords (comma‑separated) <input name="keywords" id="keywords" value="<?=htmlspecialchars($keywords)?>"> </label> <label>Link URL (optional) <input type="url" name="linkurl" id="linkurl" value="<?=htmlspecialchars($linkurl)?>"> </label> <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:1rem"> <label># Sections <select name="sections" id="sections"><?php for($i=1;$i<=8;$i++):?><option <?=$sections==$i?'selected':''?>><?=$i?></option><?php endfor;?></select> </label> <label># Paragraphs/Section <select name="paras" id="paras"><?php for($i=1;$i<=6;$i++):?><option <?=$paras==$i?'selected':''?>><?=$i?></option><?php endfor;?></select> </label> <label>Language <select name="lang" id="lang"><?php foreach($langs as $l):?><option <?=$lang===$l?'selected':''?>><?=$l?></option><?php endforeach;?></select> </label> <label>Style <select name="style" id="style"><?php foreach($styles as $s):?><option <?=$style===$s?'selected':''?>><?=$s?></option><?php endforeach;?></select> </label> <label>Tone <select name="tone" id="tone"><?php foreach($tones as $t):?><option <?=$tone===$t?'selected':''?>><?=$t?></option><?php endforeach;?></select> </label> </div> <label>Prompt Preview <textarea id="prompt" readonly></textarea> </label> <button type="button" class="primary copyBtn" id="copyPrompt" hidden>Copy Prompt</button> <button type="submit" name="generate" class="primary">Generate Article</button> </form> <?php if($html): ?> <h3>HTML Source</h3> <textarea id="rawHTML" readonly style="min-height:160px"><?=htmlspecialchars($html)?></textarea> <button type="button" class="primary copyBtn" id="copyRaw">Copy HTML</button> <h3>Rendered Preview</h3> <div class="preview" id="renderPreview"></div> <button type="button" class="primary copyBtn" id="copyRendered">Copy Rendered HTML</button> <?php endif; ?> <?php else: ?> <article class="preview"><h2>Get started</h2><p>Save your API key above to unlock the generator.</p></article> <?php endif; ?> </div><!-- /container --> <script> (()=>{ /* ---- Speech mic ---- */ const micBtn=document.getElementById('micBtn'); if(micBtn){ const rec = window.SpeechRecognition||window.webkitSpeechRecognition; if(!rec){micBtn.style.display='none';}else{ const recog=new rec(); recog.lang='en-US'; recog.maxAlternatives=1; recog.onresult=e=>{document.getElementById('topic').value=e.results[0][0].transcript; build();}; micBtn.onclick=()=>{try{recog.start();}catch{}}; } } /* ---- Build prompt live ---- */ const ids=['topic','keywords','linkurl','sections','paras','lang','style','tone']; ids.forEach(id=>document.getElementById(id)?.addEventListener('input',build)); build(); function build(){ const g=id=>document.getElementById(id).value.trim(); const topic=g('topic'); if(!topic){toggleCopies(false); return;} const kw=g('keywords'), link=g('linkurl'); const prompt=`Write a ${g('lang')} ${g('style')} article in a ${g('tone')} tone about «${topic}». ` +`Use ${g('sections')} sections (each <h2>) & ${g('paras')} paragraph${g('paras')>1?'s':''} per section. ` +`${kw?`Include keywords: ${kw}. `:''}${(kw&&link)?`Hyperlink each keyword to ${link}. `:''}` +`Append <p class="excerpt">Excerpt: …</p>. Return ONLY HTML.`; const box=document.getElementById('prompt'); box.value=prompt; toggleCopies(true); } function toggleCopies(show){ ['copyPrompt'].forEach(id=>{const b=document.getElementById(id);if(b) b.hidden=!show;}); } /* ---- copy helpers ---- */ function makeCopy(btnId, selector){ const btn=document.getElementById(btnId); if(!btn) return; btn.onclick=()=>{ const txt=typeof selector==='function'?selector():document.querySelector(selector)?.value||''; navigator.clipboard.writeText(txt).then(()=>{btn.textContent='Copied!'; setTimeout(()=>btn.textContent='Copy',1200);}); }; } makeCopy('copyPrompt','#prompt'); makeCopy('copyRaw','#rawHTML'); makeCopy('copyRendered',()=>document.getElementById('renderPreview').innerHTML); /* ---- inject rendered preview ---- */ <?php if($html): ?> document.getElementById('renderPreview').innerHTML = <?=json_encode($html)?>; document.getElementById('renderPreview').scrollIntoView({behavior:'smooth'}); <?php endif; ?> })(); </script> </body></html>
Save changes
Create folder
writable 0777
Create
Cancel