'failure', 'message' => 'Forbidden. Admin access required.', ], JSON_UNESCAPED_UNICODE); exit; } $id = filterRequest("id"); $version = filterRequest("version"); if (empty($id) || empty($version)) { jsonError("Both id and version are required.", 400); } // شكل الإصدار: أرقام ونقاط فقط (مثل 1.2.3) — يمنع أي محتوى آخر. if (!preg_match('/^\d+(\.\d+){0,3}$/', $version)) { jsonError("Invalid version format. Use digits separated by dots, e.g. 1.4.2", 400); } /** * سابقاً كان الاستعلام يُبنى بدمج القيم مباشرة: * "UPDATE packageInfo SET version ='$version' WHERE id = '$id'" * وهو حقن SQL مباشر — أي مستخدم يملك توكناً صالحاً كان يستطيع تنفيذ ما يشاء * على قاعدة البيانات عبر حقل الإصدار. الآن القيم مرتبطة كمعاملات. */ $stmt = $con->prepare("UPDATE `packageInfo` SET `version` = :version WHERE `id` = :id"); $stmt->execute([ ':version' => $version, ':id' => $id, ]); if (function_exists('logAudit')) { try { logAudit($con, (string) ($user_id ?? 'unknown'), 'تحديث إصدار التطبيق', 'packageInfo', $id, [ 'version' => $version, ]); } catch (Throwable $e) { error_log("[updatePackages] audit failed: " . $e->getMessage()); } } if ($stmt->rowCount() > 0) { jsonSuccess(['id' => $id, 'version' => $version], "Package version updated successfully for ID $id"); } else { jsonError("No package row was updated — check that ID $id exists and the version differs.", 404); }