2010-10-23 18 views
31

Encontré dos funciones para obtener datos de cookies con Javascript, una en w3schools.com y otra en quirksmode.org
Me gustaría saber cuál debo usar?Javascript getCookie functions

Por ejemplo, creo que leí en alguna parte que había un problema con algunos navegadores que dividían el punto y coma ;?

w3schools:

function getCookie(c_name) { 
    if (document.cookie.length > 0) { 
     c_start = document.cookie.indexOf(c_name + "="); 
     if (c_start != -1) { 
      c_start = c_start + c_name.length + 1; 
      c_end = document.cookie.indexOf(";", c_start); 
      if (c_end == -1) c_end = document.cookie.length; 
      return unescape(document.cookie.substring(c_start, c_end)); 
     } 
    } 
    return ""; 
} 

quirksmode:

function readCokie(name) { 
    var nameEQ = name + "="; 
    var ca = document.cookie.split(';'); 
    for(var i = 0; i < ca.length; i++) { 
     var c = ca[i]; 
     while (c.charAt(0) == ' ') c = c.substring(1, c.length); 
     if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 
    } 
    return null; 
} 
+0

Los dos van en busca de ';' caracteres para dividir las cookies, que por lo que yo sé es siempre correcta. – VoteyDisciple

+0

La función 'getCookie' es incorrecta, piense en lo que sucede si obtiene unas cookies llamadas' ART = 'y usted tiene una cookie llamada' SMART = ' –

+1

w3schools ha cambiado su función getCookie (vea http: //www.w3schools .com/js/js_cookies.asp), probablemente funcione mejor ahora. – pauloya

Respuesta

86

La función de W3CSchool es incorrecta. Se produce un error si hay varias cookies que tienen el mismo sufijo como:

ffoo=bar; foo=baz 

Cuando busca foo devolverá el valor de ffoo en lugar de foo .

Ahora esto es lo que haría: Antes que nada, debe conocer la sintaxis de cómo se transportan las cookies. especificación original de Netscape (sólo hay copias disponibles como this one at haxx.se) usa punto y coma para separar varias galletas mientras que cada par nombre/valor tiene la siguiente sintaxis:

NOMBRE=VALOR
Esta cadena es una secuencia de caracteres excluyendo punto y coma, coma y espacio en blanco. Si existe la necesidad de colocar dichos datos en el nombre o valor, se recomienda algún método de codificación, como la codificación de estilo URL %XX, aunque no se define ni se requiere ninguna codificación.

Por lo tanto, dividir document.cookie cadena en punto y coma o comas es una opción viable.

Además de eso, RFC 2109 qué también especifican que las cookies están separados por cualquiera de punto y coma o comas:

cookie   =  "Cookie:" cookie-version 
         1*((";" | ",") cookie-value) 
cookie-value =  NAME "=" VALUE [";" path] [";" domain] 
cookie-version =  "$Version" "=" value 
NAME   =  attr 
VALUE   =  value 
path   =  "$Path" "=" value 
domain   =  "$Domain" "=" value 

Aunque ambos están permitidos, se prefieren comas ya que son el separador predeterminado de lista artículos en HTTP.

Nota: Para compatibilidad hacia atrás, el separador en la cabecera de la galleta es punto y coma (;) en todas partes. Un servidor también debe aceptar coma (,) como el separador entre los valores de cookie para una futura compatibilidad.

Por otra parte, el par nombre/valor tiene algunas restricciones adicionales como el VALOR también puede ser una cadena entre comillas como se especifica en RFC 2616:

attr  =  token 
value  =  token | quoted-string 

Así pues, estas dos versiones de galletas necesitan debe tratarse por separado:

if (typeof String.prototype.trimLeft !== "function") { 
    String.prototype.trimLeft = function() { 
     return this.replace(/^\s+/, ""); 
    }; 
} 
if (typeof String.prototype.trimRight !== "function") { 
    String.prototype.trimRight = function() { 
     return this.replace(/\s+$/, ""); 
    }; 
} 
if (typeof Array.prototype.map !== "function") { 
    Array.prototype.map = function(callback, thisArg) { 
     for (var i=0, n=this.length, a=[]; i<n; i++) { 
      if (i in this) a[i] = callback.call(thisArg, this[i]); 
     } 
     return a; 
    }; 
} 
function getCookies() { 
    var c = document.cookie, v = 0, cookies = {}; 
    if (document.cookie.match(/^\s*\$Version=(?:"1"|1);\s*(.*)/)) { 
     c = RegExp.$1; 
     v = 1; 
    } 
    if (v === 0) { 
     c.split(/[,;]/).map(function(cookie) { 
      var parts = cookie.split(/=/, 2), 
       name = decodeURIComponent(parts[0].trimLeft()), 
       value = parts.length > 1 ? decodeURIComponent(parts[1].trimRight()) : null; 
      cookies[name] = value; 
     }); 
    } else { 
     c.match(/(?:^|\s+)([!#$%&'*+\-.0-9A-Z^`a-z|~]+)=([!#$%&'*+\-.0-9A-Z^`a-z|~]*|"(?:[\x20-\x7E\x80\xFF]|\\[\x00-\x7F])*")(?=\s*[,;]|$)/g).map(function($0, $1) { 
      var name = $0, 
       value = $1.charAt(0) === '"' 
          ? $1.substr(1, -1).replace(/\\(.)/g, "$1") 
          : $1; 
      cookies[name] = value; 
     }); 
    } 
    return cookies; 
} 
function getCookie(name) { 
    return getCookies()[name]; 
} 
+6

muchas gracias por el código a prueba de balas. – FFish

+1

Me gustaría mover 'trimRight' y' trimLeft' fuera de la función 'getCookie': solo tiene que configurarlos una vez. –

+0

@Tim Down: Sí, tienes razón. – Gumbo

6

Esto, desde w3schools, es incorrecta ya que puede conducir a conseguir la cookie equivocada:

c_start = document.cookie.indexOf(c_name + "="); 

Si vas l buscando una cookie llamada foo (que supondremos que es una cookie existente) entonces en algún lugar en document.cookie será la cadena foo=bar.

Sin embargo, no hay garantía de que no también ser la cadena xfoo=something. Observe que esto todavía contiene la subcadena foo=, por lo que el código de w3schools lo encontrará. Y si la cookie xfoo aparece primero en la lista, recibirá el valor something (¡incorrectamente!) En lugar del bar esperado.

Dada la elección entre dos piezas de código, nunca vaya con la que está fundamentalmente rota.

8

Sí, t La solución W3Schools es incorrecta.

Para aquellos que les gustaría, aquí hay una solución más simple que funciona. Simplemente precede un espacio, por lo que la única llamada a indexOf() solo devuelve la cookie correcta.

function getCookie(c_name) { 
    var c_value = " " + document.cookie; 
    var c_start = c_value.indexOf(" " + c_name + "="); 
    if (c_start == -1) { 
     c_value = null; 
    } 
    else { 
     c_start = c_value.indexOf("=", c_start) + 1; 
     var c_end = c_value.indexOf(";", c_start); 
     if (c_end == -1) { 
      c_end = c_value.length; 
     } 
     c_value = unescape(c_value.substring(c_start,c_end)); 
    } 
    return c_value; 
} 
1

Todo el código mostrado arriba está ROTO. Los dos problemas comunes son (1) la función getcookie puede devolver el valor incorrecto si un nombre de cookie es un sufijo apropiado de otro nombre de cookie; y (2) la función setcookie no protege el valor de la cookie, lo que significa que si el valor de la cookie incluye (por ejemplo) un ";" entonces todas las cookies están dañadas y no se pueden analizar.

TL; DR utilizar esta biblioteca bien escrito en su lugar: https://github.com/js-cookie/js-cookie

+0

Intenté la respuesta aceptada para valores de cookie de comillas dobles que contengan signos iguales, y no funcionó, pero js-cookie hizo el trabajo. – dlauzon

Cuestiones relacionadas