soil-print-combined.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. /**
  3. * soil-print-combined.php
  4. *
  5. * Combined print/PDF page: Soil Analysis + Soil Report in one document.
  6. * Uses two iframes pointing at the existing individual pages to avoid
  7. * duplicating any rendering logic.
  8. *
  9. * Accessed by headlessChrome_pdf.php (type=soil) — never directly by users.
  10. * Auth is via the shared ptoken written by the generator.
  11. *
  12. * Both child iframes receive the same ptoken. authenticatePrintPage() does
  13. * not delete the token file, so multiple requests with the same token work.
  14. */
  15. require_once __DIR__ . '/../../../config/database.php';
  16. require_once __DIR__ . '/../../../lib/auth.php';
  17. require_once __DIR__ . '/../../../lib/print_auth.php';
  18. if (session_status() === PHP_SESSION_NONE) {
  19. session_start();
  20. }
  21. $recordId = (int) ($_GET['rid'] ?? 0);
  22. $randId = trim( $_GET['rand'] ?? '');
  23. $clientId = (int) ($_GET['cid'] ?? 0);
  24. $stid = trim( $_GET['stid'] ?? '');
  25. $ptoken = trim( $_GET['ptoken'] ?? '');
  26. authenticatePrintPage($recordId, $randId);
  27. // Build child page URLs — pass the same ptoken so each iframe can auth
  28. $coverpageUrl = '/dashboard/crop-analysis/coverpage.php?'
  29. . http_build_query([
  30. 'type' => 'soil',
  31. 'rid' => $recordId,
  32. 'rand' => $randId,
  33. 'cid' => $clientId,
  34. 'stid' => $stid,
  35. 'ptoken' => $ptoken,
  36. 'print' => '1',
  37. ]);
  38. // Build child page URLs — pass the same ptoken so each iframe can auth
  39. $analysisUrl = '/dashboard/crop-analysis/soil-test-data/soil-analysis.php?'
  40. . http_build_query([
  41. 'rid' => $recordId,
  42. 'rand' => $randId,
  43. 'cid' => $clientId,
  44. 'stid' => $stid,
  45. 'ptoken' => $ptoken,
  46. 'print' => '1',
  47. ]);
  48. $reportUrl = '/dashboard/crop-analysis/soil-test-data/soil-report-pdf.php?'
  49. . http_build_query([
  50. 'rid' => $recordId,
  51. 'rand' => $randId,
  52. 'ptoken' => $ptoken,
  53. ]);
  54. function h(string $v): string {
  55. return htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
  56. }
  57. ?>
  58. <!doctype html>
  59. <html lang="en">
  60. <head>
  61. <meta charset="UTF-8">
  62. <title>Soil Analysis &amp; Report</title>
  63. <style>
  64. * { margin: 0; padding: 0; box-sizing: border-box; }
  65. body { background: #fff; }
  66. iframe {
  67. width: 100%;
  68. border: none;
  69. display: block;
  70. min-height: 200px;
  71. }
  72. .page-section {
  73. page-break-after: always;
  74. }
  75. .page-section:last-child {
  76. page-break-after: avoid;
  77. }
  78. @media print {
  79. @page {
  80. size: A4 portrait;
  81. margin: 0;
  82. }
  83. html, body {
  84. margin: 0;
  85. padding: 0;
  86. background: #fff;
  87. }
  88. .page {
  89. padding: 0;
  90. box-sizing: border-box;
  91. }
  92. body {
  93. min-width: 1030px !important;
  94. font-size: 0.75em;
  95. }
  96. .container {
  97. min-width: 1030px !important;
  98. }
  99. .report-textarea {
  100. border:none;
  101. }
  102. }
  103. </style>
  104. </head>
  105. <body>
  106. <div class="page-section page">
  107. <iframe id="frame-coverpage" src="<?= h($coverpageUrl) ?>" scrolling="no"></iframe>
  108. </div>
  109. <div class="page-section page">
  110. <iframe id="frame-analysis" src="<?= h($analysisUrl) ?>" scrolling="no"></iframe>
  111. </div>
  112. <div class="page-section page">
  113. <iframe id="frame-report" src="<?= h($reportUrl) ?>" scrolling="no"></iframe>
  114. </div>
  115. <script>
  116. (function () {
  117. function resizeFrame(iframe) {
  118. try {
  119. var h = iframe.contentDocument.documentElement.scrollHeight;
  120. if (h > 0) iframe.style.height = h + 'px';
  121. } catch (e) {
  122. iframe.style.height = '2970px'; // A4 height fallback (~297mm at 96dpi)
  123. }
  124. }
  125. // Cover page is always exactly one A4 page.
  126. // The combined viewport is 1030px wide; Chrome scales it to 210mm for print.
  127. // Height must be 1030 * (297/210) = 1457px so it fills the full A4 height after scaling.
  128. var cover = document.getElementById('frame-coverpage');
  129. if (cover) cover.style.height = '1457px';
  130. ['frame-analysis', 'frame-report'].forEach(function (id) {
  131. var el = document.getElementById(id);
  132. el.addEventListener('load', function () { resizeFrame(el); });
  133. });
  134. })();
  135. </script>
  136. </body>
  137. </html>