updateSoilSpecification.php 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. /**
  3. * controllers/updateSoilSpecification.php
  4. *
  5. * AJAX POST handler: updates a single cell in soil_specifications.
  6. * Returns JSON { success: true } or { success: false, error: "..." }.
  7. */
  8. if (session_status() === PHP_SESSION_NONE) {
  9. session_start();
  10. }
  11. require_once __DIR__ . '/../config/database.php';
  12. require_once __DIR__ . '/../lib/auth.php';
  13. require_once __DIR__ . '/../lib/csrf.php';
  14. header('Content-Type: application/json');
  15. if (!isLoggedIn()) {
  16. http_response_code(401);
  17. echo json_encode(['success' => false, 'error' => 'Not authenticated']);
  18. exit;
  19. }
  20. if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
  21. http_response_code(405);
  22. echo json_encode(['success' => false, 'error' => 'Method not allowed']);
  23. exit;
  24. }
  25. if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) {
  26. http_response_code(403);
  27. echo json_encode(['success' => false, 'error' => 'Invalid CSRF token']);
  28. exit;
  29. }
  30. $specId = (int)($_POST['spec_id'] ?? 0);
  31. $column = (string)($_POST['column'] ?? '');
  32. $value = trim((string)($_POST['value'] ?? ''));
  33. if (!$specId || $column === '') {
  34. http_response_code(400);
  35. echo json_encode(['success' => false, 'error' => 'Missing required fields']);
  36. exit;
  37. }
  38. // Allowlist — only columns present in soil_specifications (excluding system cols)
  39. $allowed = [
  40. 'soil_type',
  41. 'cec', 'NO3_N', 'NH3_N',
  42. 'p_mehlick', 'p_bray2', 'p_morgan', 'p_colwell',
  43. 'k_morgan', 'ca_morgan', 'mg_morgan', 'na_morgan',
  44. 'ch_h2o', 'ocarbon', 'omatter', 'fe', 'ec',
  45. 'ph_cacl2', 'ph_h2o', 's_morgan',
  46. 'b_cacl2', 'mn_dtpa', 'zn_dtpa', 'fe_dtpa', 'cu_dtpa',
  47. 'al', 'sl_cacl2', 'm_dtpa', 'co_dtpa', 'se',
  48. 'ca_mehlick3', 'mg_mehlick3', 'k_mehlick3', 'na_mehlick3', 'al_mehlick3',
  49. 'BS_ca2', 'BS_ca_ppm', 'BS_mg2', 'BS_mg_ppm',
  50. 'BS_k', 'BS_k_ppm', 'BS_na', 'BS_na_ppm',
  51. 'BS_al3', 'BS_ob', 'BS_h',
  52. 'ca_mg_ratio', 'c_n_ratio',
  53. // spec-range columns
  54. 'ca_ppm_min', 'ca_ppm_max', 'mg_ppm_min', 'mg_ppm_max',
  55. 'k_ppm_min', 'k_ppm_max', 'na_ppm_min', 'na_ppm_max',
  56. 'cabs_min', 'cabs_max', 'mgbs_min', 'mgbs_max',
  57. 'kbs_min', 'kbs_max', 'nabs_min', 'nabs_max',
  58. 'ob_rec', 'h_rec', 'ca_mg_ratio', 'c_n_ratio', 'ph',
  59. ];
  60. if (!in_array($column, $allowed, true)) {
  61. http_response_code(400);
  62. echo json_encode(['success' => false, 'error' => 'Column not editable']);
  63. exit;
  64. }
  65. try {
  66. $pdo = getDBConnection();
  67. $userId = getCurrentUserId();
  68. // The backtick-quoted column name is safe because it is validated against the allowlist above.
  69. $stmt = $pdo->prepare("UPDATE soil_specifications SET `{$column}` = ? WHERE id = ? AND modx_user_id = ?");
  70. $stmt->execute([$value, $specId, $userId]);
  71. if ($stmt->rowCount() === 0) {
  72. http_response_code(404);
  73. echo json_encode(['success' => false, 'error' => 'Record not found']);
  74. exit;
  75. }
  76. echo json_encode(['success' => true]);
  77. } catch (PDOException $e) {
  78. error_log('DB error in updateSoilSpecification.php: ' . $e->getMessage());
  79. http_response_code(500);
  80. echo json_encode(['success' => false, 'error' => 'Database error']);
  81. }
  82. exit;