print_auth.php 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. <?php
  2. /**
  3. * lib/print_auth.php
  4. *
  5. * Shared authentication for PDF print pages.
  6. *
  7. * Print pages can be accessed two ways:
  8. * 1. Normal browser access — requires an active PHP session (requireLogin)
  9. * 2. Headless Chrome access — no session; validated via a one-time token
  10. * file written by pdf-files/headlessChrome_pdf.php
  11. *
  12. * Usage (at the top of any print page, after requireLogin is available):
  13. *
  14. * require_once __DIR__ . '/../../../lib/print_auth.php';
  15. * $chromeAccess = authenticatePrintPage($recordId, $randId);
  16. * $userId = $chromeAccess ? null : getCurrentUserId();
  17. */
  18. /**
  19. * Authenticate a print page request.
  20. *
  21. * Returns true if access was granted via a valid headless Chrome ptoken.
  22. * Returns false if access was granted via normal session login.
  23. * Dies with 403 if neither is valid.
  24. */
  25. function authenticatePrintPage(int $recordId, string $randId): bool
  26. {
  27. $ptoken = trim($_GET['ptoken'] ?? '');
  28. if ($ptoken !== '') {
  29. // Validate token format first (prevents path traversal)
  30. if (!preg_match('/^[a-f0-9]{32}$/', $ptoken)) {
  31. http_response_code(403);
  32. die('Invalid print token.');
  33. }
  34. $tokenFile = dirname(__DIR__) . '/pdf-files/tokens/' . $ptoken . '.tmp';
  35. if (!file_exists($tokenFile)) {
  36. http_response_code(403);
  37. die('Print token not found or already used.');
  38. }
  39. $tokenData = json_decode(file_get_contents($tokenFile), true);
  40. if (
  41. !is_array($tokenData)
  42. || (int)$tokenData['rid'] !== $recordId
  43. || $tokenData['rand'] !== $randId
  44. || (int)$tokenData['expires'] < time()
  45. ) {
  46. @unlink($tokenFile);
  47. http_response_code(403);
  48. die('Invalid or expired print token.');
  49. }
  50. // Token is valid — do NOT delete here; Chrome may make multiple requests
  51. // for embedded resources. The generator deletes it after Chrome finishes.
  52. return true;
  53. }
  54. // Fall back to session auth
  55. requireLogin();
  56. return false;
  57. }