generate_docx.php 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. <?php
  2. // generate_docx.php
  3. declare(strict_types=1);
  4. ini_set('display_errors','0'); error_reporting(E_ALL);
  5. use PhpOffice\PhpWord\PhpWord;
  6. use PhpOffice\PhpWord\IOFactory;
  7. use PhpOffice\PhpWord\Shared\Html;
  8. use PhpOffice\PhpWord\ComplexType\TblWidth;
  9. use PhpOffice\PhpWord\Style\TOC as TOCStyle;
  10. header('Content-Type: application/json; charset=utf-8');
  11. header('Access-Control-Allow-Methods: POST, OPTIONS');
  12. header('Access-Control-Allow-Headers: Content-Type');
  13. if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') { http_response_code(204); exit; }
  14. require __DIR__ . '/vendor/autoload.php';
  15. try {
  16. $raw = file_get_contents('php://input') ?: '{}';
  17. $in = json_decode($raw, true) ?: [];
  18. $md = (string)($in['markdown'] ?? '');
  19. $ctx = (array)($in['context'] ?? []);
  20. if ($md === '') throw new RuntimeException('Missing markdown');
  21. // Simple Markdown → HTML
  22. $parsedown = new Parsedown();
  23. $parsedown->setBreaksEnabled(true);
  24. $htmlBody = $parsedown->text($md);
  25. $address = $ctx['address'] ?? '';
  26. $preparedFor = $ctx['prepared_for'] ?? '—';
  27. $preparedBy = $ctx['prepared_by'] ?? 'Modulos Design';
  28. $when = date('j F Y');
  29. $intent = trim((string)($ctx['project_intent'] ?? ''));
  30. $pw = new PhpWord();
  31. // Base styles
  32. $pw->addTitleStyle(1, ['size'=>20,'bold'=>true,'color'=>'1f2937']);
  33. $pw->addTitleStyle(2, ['size'=>16,'bold'=>true,'color'=>'334155']);
  34. $pw->addTitleStyle(3, ['size'=>13,'bold'=>true,'color'=>'475569']);
  35. $pw->setDefaultFontName('Calibri');
  36. $pw->setDefaultFontSize(11);
  37. // COVER SECTION
  38. $cover = $pw->addSection();
  39. $cover->addText('Supporting Planning Report', ['bold'=>true,'size'=>28,'color'=>'0f172a'], ['spaceAfter'=>240]);
  40. if ($address) $cover->addText('Address: '.$address, [], ['spaceAfter'=>120]);
  41. $cover->addText('Prepared for: '.$preparedFor);
  42. $cover->addText('Prepared by: '.$preparedBy);
  43. $cover->addText('Date: '.$when);
  44. if ($intent) { $cover->addTextBreak(1); $cover->addText('Project intent: '.$intent, ['italic'=>true]); }
  45. $cover->addPageBreak();
  46. // TOC SECTION
  47. $toc = $pw->addSection();
  48. $toc->addText('Contents', ['bold'=>true,'size'=>18], ['spaceAfter'=>200]);
  49. $pw->addTableStyle('TOCStyle', [], ['indent'=>0, 'tabLeader'=>TOCStyle::TABLEADER_DOT]);
  50. $toc->addTOC(['size'=>11], ['tabLeader'=>TOCStyle::TABLEADER_DOT, 'indent'=>0, 'name'=>'TOCStyle']);
  51. $toc->addPageBreak();
  52. // BODY SECTION (inject HTML; Parsedown produced h1/h2/h3 → Word titles)
  53. $body = $pw->addSection();
  54. Html::addHtml($body, $htmlBody, false, false);
  55. // Save to tmp and stream URL back (or data URI)
  56. $tmpDir = sys_get_temp_dir();
  57. $file = $tmpDir . '/PlanningReport-' . preg_replace('~[^\w\-]+~','_', $address ?: 'Site') . '.docx';
  58. IOFactory::createWriter($pw, 'Word2007')->save($file);
  59. echo json_encode(['ok'=>true, 'url'=>"download.php?file=".basename($file)]);
  60. } catch (Throwable $e) {
  61. http_response_code(500);
  62. echo json_encode(['ok'=>false,'error'=>$e->getMessage()]);
  63. }