« Back to History
resume_builder.php
|
20260722_120325.php
Initial Domain Snapshot
Copy Code
<?php // resume_builder.php (print-safe, single-file) // Note: Remove or set display_errors=0 in production ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); // ---------- Server-side PDF export ---------- if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'export_pdf') { $html = $_POST['resume_html'] ?? ''; if (trim($html) === '') { echo "No resume HTML received."; exit; } // If Dompdf is available via composer, use it if (file_exists(__DIR__ . '/vendor/autoload.php')) { require_once __DIR__ . '/vendor/autoload.php'; $dompdf = new \Dompdf\Dompdf(); // Optional: set base path for resolving relative assets $dompdf->loadHtml($html); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); $pdf = $dompdf->output(); header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename="resume.pdf"'); echo $pdf; exit; } else { // Fallback: send HTML file header('Content-Type: text/html; charset=utf-8'); header('Content-Disposition: attachment; filename="resume.html"'); echo $html; exit; } } // ---------- UI / Builder ---------- ?> <!doctype html> <html lang="hi"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Resume Builder — mistermanager.in</title> <style> :root{--muted:#666;--accent:#2563eb} body{font-family:Arial,Helvetica,sans-serif;margin:0;padding:20px;background:#f4f6f8;color:#111} .container{max-width:1100px;margin:0 auto;display:grid;grid-template-columns:1fr 520px;gap:20px} form{background:#fff;padding:18px;border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,0.06);box-sizing:border-box} .panel{background:#fff;padding:16px;border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,0.04)} h2{margin-top:0} label{display:block;margin:8px 0 4px;font-weight:600} input[type=text], input[type=email], input[type=tel], input[type=date], textarea{width:100%;padding:8px;border:1px solid #d8dbe0;border-radius:6px;box-sizing:border-box} textarea{min-height:80px} .row{display:flex;gap:8px} .row>*{flex:1} button{background:var(--accent);color:#fff;border:0;padding:8px 12px;border-radius:6px;cursor:pointer} .muted{color:var(--muted);font-size:13px} .small{font-size:13px} .skill-pill{display:inline-block;padding:6px 10px;border-radius:20px;border:1px solid #e2e8f0;margin:4px 8px 4px 0} /* spacing fixed */ .exp-item{margin-bottom:8px;padding:10px;border:1px solid #f0f3f6;border-radius:6px} .footer-note{font-size:11px;color:#777;margin-top:24px;text-align:center} /* Preview / resume styles */ #resume-preview{padding:24px;background:#fff;border-radius:6px;border:1px solid #e2e8f0;min-height:420px;box-sizing:border-box} .resume-page{max-width:760px;margin:0 auto;color:#0f172a} .resume-header{display:flex;align-items:flex-start;gap:16px;flex-wrap:nowrap} .avatar-wrap{flex:0 0 auto} .avatar{width:88px;height:88px;border-radius:8px;object-fit:cover;border:2px solid #e6eefc;display:inline-block} .name{font-size:20px;font-weight:700;margin:0} .title{color:#475569;margin:4px 0} .section{margin-top:14px} .section h3{margin:0 0 8px 0;font-size:15px;border-bottom:1px dashed #e6eefc;padding-bottom:6px} .entry{margin-bottom:10px} .muted-small{color:var(--muted);font-size:13px} .page-footer{margin-top:32px;text-align:center;font-size:11px;color:#888} /* Print-safe rules */ @media print{ body{background:#fff;padding:10px} .container{grid-template-columns:1fr} form,.panel{box-shadow:none;border:0} button{display:none} /* Ensure avatar does not scale to full page */ .avatar{width:88px !important;height:88px !important;object-fit:cover !important;display:inline-block !important} /* Prevent image from overflowing */ img{max-width:100% !important;height:auto !important} /* Avoid breaking the resume header across pages */ .resume-header{page-break-inside:avoid} .section{page-break-inside:avoid} .entry{page-break-inside:avoid} /* Keep footer on each printed page bottom (Dompdf/Browser behavior dependent) */ .page-footer{position:relative} #resume-preview{padding:0;border:0} } /* small screens */ @media (max-width:900px){ .container{grid-template-columns:1fr} } </style> </head> <body> <div class="container"> <form id="builder" onsubmit="return false;"> <h2>Resume Builder</h2> <label>पूरा नाम</label> <input type="text" id="fullName" placeholder="जैसे — राजेश कुमार"> <label>पद / प्रोफेशन (Title)</label> <input type="text" id="title" placeholder="जैसे — PHP Developer"> <div class="row"> <div> <label>Email</label> <input type="email" id="email" placeholder="your@email.com"> </div> <div> <label>Phone</label> <input type="tel" id="phone" placeholder="+91-9876543210"> </div> </div> <label>पता (Address)</label> <textarea id="address" placeholder="पूरा पता लिखें (शहर, राज्य, पिन कोड सहित)"></textarea> <label>निजी सारांश (Summary)</label> <textarea id="summary" placeholder="अपने बारे में संक्षेप में बताएं"></textarea> <label>प्रोफ़ाइल फ़ोटो (optional)</label> <input type="file" id="photo" accept="image/*"> <hr> <h3 class="small">अनुभव (Experience)</h3> <div id="experience-list"></div> <button type="button" onclick="addExperience()">+ नया अनुभव जोड़ें</button> <hr> <h3 class="small">शिक्षा (Education)</h3> <div id="education-list"></div> <button type="button" onclick="addEducation()">+ नया शिक्षा आइटम जोड़ें</button> <hr> <label>कुशलताएँ (comma separated)</label> <input type="text" id="skills" placeholder="e.g. PHP, MySQL, HTML, CSS"> <hr> <div style="display:flex;gap:8px;flex-wrap:wrap"> <button type="button" onclick="renderPreview()">Preview बनाएँ</button> <button type="button" onclick="exportPDF()">PDF Export (browser)</button> <button type="button" onclick="exportPDFServer()">PDF Export (server-side)</button> </div> <div class="footer-note">Created by mistermanager.in</div> </form> <div class="panel"> <h2>Preview</h2> <div id="resume-preview"> <p class="muted">पहले “Preview बनाएँ” दबाएँ।</p> </div> </div> </div> <!-- Templates --> <template id="exp-template"> <div class="exp-item"> <div class="row"> <input type="text" class="exp-role" placeholder="Role / पद"> <input type="text" class="exp-company" placeholder="Company / संस्था"> </div> <div class="row" style="margin-top:6px;align-items:center"> <input type="date" class="exp-start" placeholder="Start"> <input type="date" class="exp-end" placeholder="End"> </div> <div style="margin-top:6px;display:flex;gap:8px;align-items:center"> <label style="font-weight:500"><input type="checkbox" class="exp-present"> Present</label> </div> <textarea class="exp-desc" placeholder="किए गए कार्यों का संक्षेप (description)" style="margin-top:8px"></textarea> <div style="margin-top:8px"><button type="button" onclick="removeNode(this)">Remove</button></div> </div> </template> <template id="edu-template"> <div class="edu-item"> <div class="row"> <input type="text" class="edu-degree" placeholder="Degree / डिग्री"> <input type="text" class="edu-school" placeholder="Institute / संस्थान"> </div> <div class="row" style="margin-top:6px"> <input type="text" class="edu-year" placeholder="Year"> <input type="text" class="edu-grade" placeholder="Grade / Percentage"> </div> <div style="margin-top:8px"><button type="button" onclick="removeNode(this)">Remove</button></div> </div> </template> <script> // helpers function addExperience(){ const tpl = document.getElementById('exp-template').content.cloneNode(true); document.getElementById('experience-list').appendChild(tpl); // attach present behavior const latest = document.getElementById('experience-list').lastElementChild; const presentCb = latest.querySelector('.exp-present'); const endInput = latest.querySelector('.exp-end'); presentCb.addEventListener('change', ()=>{ endInput.disabled = presentCb.checked; }); } function addEducation(){ const tpl = document.getElementById('edu-template').content.cloneNode(true); document.getElementById('education-list').appendChild(tpl); } function removeNode(btn){ const exp = btn.closest('.exp-item'); const edu = btn.closest('.edu-item'); if(exp) exp.remove(); if(edu) edu.remove(); } function escapeHtml(s){ if(!s) return ''; return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,'''); } function nl2br(s){ return String(s).replace(/\n/g,'<br>'); } function fileToDataUrl(file){ return new Promise((res,rej)=>{ const r = new FileReader(); r.onload = ()=>res(r.result); r.onerror = rej; r.readAsDataURL(file); }); } function formatDateDisplay(dateStr){ if(!dateStr) return ''; try{ const d = new Date(dateStr); if(isNaN(d)) return dateStr; return d.toLocaleString('default',{month:'short',year:'numeric'}); } catch(e){ return dateStr; } } async function renderPreview(){ const name = document.getElementById('fullName').value; const title = document.getElementById('title').value; const email = document.getElementById('email').value; const phone = document.getElementById('phone').value; const address = document.getElementById('address').value; const summary = document.getElementById('summary').value; const skills = document.getElementById('skills').value; let photoData = ''; const photoEl = document.getElementById('photo'); if(photoEl.files && photoEl.files[0]) photoData = await fileToDataUrl(photoEl.files[0]); const expNodes = Array.from(document.querySelectorAll('.exp-item')); const experiences = expNodes.map(n=>{ const start = n.querySelector('.exp-start')?.value || ''; const end = n.querySelector('.exp-end')?.value || ''; const present = n.querySelector('.exp-present')?.checked || false; return { role: n.querySelector('.exp-role')?.value || '', company: n.querySelector('.exp-company')?.value || '', start, end, present, desc: n.querySelector('.exp-desc')?.value || '' }; }); const eduNodes = Array.from(document.querySelectorAll('.edu-item')); const education = eduNodes.map(n=>({ degree: n.querySelector('.edu-degree')?.value||'', school: n.querySelector('.edu-school')?.value||'', year: n.querySelector('.edu-year')?.value||'', grade: n.querySelector('.edu-grade')?.value||'' })); // build resume HTML (print-friendly) let html = ` <div class="resume-page"> <div style="display:flex;justify-content:space-between;font-size:12px;color:#666;margin-bottom:8px"> <div>${new Date().toLocaleDateString()}</div> <div>Resume</div> </div> <div class="resume-header"> ${photoData?`<div class="avatar-wrap"><img src="${photoData}" class="avatar" alt="photo"></div>`:''} <div style="flex:1 1 auto"> <h1 class="name">${escapeHtml(name)}</h1> <div class="title">${escapeHtml(title)}</div> <div class="muted-small">${escapeHtml(email)} · ${escapeHtml(phone)}</div> <div class="muted-small">${nl2br(escapeHtml(address))}</div> </div> </div> <div class="section"><h3>Summary</h3><div>${nl2br(escapeHtml(summary))}</div></div> <div class="section"><h3>Experience</h3> ${experiences.map(e=>{ const sd = formatDateDisplay(e.start); const ed = e.present ? 'Present' : (e.end ? formatDateDisplay(e.end) : ''); return `<div class="entry"><strong>${escapeHtml(e.role)}</strong> — <em>${escapeHtml(e.company)}</em> <div class="muted-small">${escapeHtml(sd)} ${sd && ed ? ' — ' : ''} ${escapeHtml(ed)}</div> <div>${nl2br(escapeHtml(e.desc))}</div></div>`; }).join('')} </div> <div class="section"><h3>Education</h3> ${education.map(ed=>`<div class="entry"><strong>${escapeHtml(ed.degree)}</strong>, ${escapeHtml(ed.school)}<div class="muted-small">${escapeHtml(ed.year)} · ${escapeHtml(ed.grade)}</div></div>`).join('')} </div> <div class="section"><h3>Skills</h3> <div>${skills.split(',').map(s=>s.trim()).filter(Boolean).map(s=>`<span class="skill-pill">${escapeHtml(s)}</span>`).join('')}</div> </div> <div class="page-footer">Created by mistermanager.in</div> </div> `; const preview = document.getElementById('resume-preview'); preview.innerHTML = html; preview.dataset.html = html; } function exportPDF(){ const preview = document.getElementById('resume-preview'); if(!preview.dataset.html){ alert('पहले Preview बनाएँ।'); return; } const w = window.open('', '_blank'); const doc = w.document.open(); doc.write('<!doctype html><html><head><meta charset="utf-8"><title>Resume</title>'); doc.write('<style>body{font-family:Arial,Helvetica,sans-serif;padding:24px;color:#111}.muted-small{color:#666}.skill-pill{display:inline-block;padding:6px 10px;border-radius:20px;border:1px solid #e2e8f0;margin:4px 8px 4px 0}.avatar{width:88px;height:88px;object-fit:cover;border-radius:8px;border:2px solid #e6eefc}</style>'); doc.write('</head><body>'); doc.write(preview.dataset.html); doc.write('</body></html>'); doc.close(); setTimeout(()=>{ w.print(); }, 600); } function exportPDFServer(){ const preview = document.getElementById('resume-preview'); if(!preview.dataset.html){ alert('पहले Preview बनाएँ।'); return; } const f = document.createElement('form'); f.method = 'POST'; f.style.display = 'none'; const a = document.createElement('input'); a.name = 'action'; a.value = 'export_pdf'; const b = document.createElement('input'); b.name = 'resume_html'; b.value = preview.dataset.html; f.appendChild(a); f.appendChild(b); document.body.appendChild(f); f.submit(); } // init addExperience(); addEducation(); </script> </body> </html>