urlencode vs rawurlencode?


380

ถ้าฉันต้องการสร้าง URL โดยใช้ตัวแปรฉันมีสองทางเลือกในการเข้ารหัสสตริง และurlencode()rawurlencode()

อะไรคือความแตกต่างและสิ่งที่ต้องการ?


1
ฉันอยากจะเห็นเหตุผลบางอย่างสำหรับการเลือกหนึ่งอย่าง (เช่นปัญหาที่อาจพบกับหนึ่งหรืออื่น ๆ ) ฉัน (และฉันคาดว่าคนอื่น ๆ ) ต้องการที่จะสามารถเลือกหนึ่งและใช้มันตลอดไปด้วย เอะอะน้อยที่สุดดังนั้นฉันจึงเริ่มให้เงินกับคำถามนี้
Kzqai

29
@Tchalvak: rawurlencodeถ้าคุณต้องการที่จะเลือกเพียงอย่างใดอย่างหนึ่งให้เลือก คุณจะไม่ค่อยพบกับ%20ระบบที่ทำให้หายใจไม่ออกเมื่อมีการเข้ารหัสช่องว่างในขณะที่ระบบที่ทำให้หายใจไม่ออกเมื่อเข้ารหัสเป็น+เรื่องปกติ
Anomie

คำตอบ:


326

มันจะขึ้นอยู่กับวัตถุประสงค์ของคุณ หากการทำงานร่วมกันกับระบบอื่นมีความสำคัญแสดงว่า rawurlencode นั้นเป็นวิธีที่จะไป ข้อยกเว้นเดียวคือระบบเดิมซึ่งคาดว่าสตริงการสืบค้นจะเป็นไปตามสไตล์การเข้ารหัสแบบฟอร์มของช่องว่างที่เข้ารหัสเป็น + แทนที่จะเป็น% 20 (ซึ่งในกรณีนี้คุณต้องมี urlencode)

rawurlencodeติดตาม RFC 1738 ก่อนหน้า PHP 5.3.0 และ RFC 3986 หลังจากนั้น (ดูhttp://us2.php.net/manual/en/function.rawurlencode.php )

ส่งคืนสตริงที่อักขระที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมดยกเว้น -_. ~ ถูกแทนที่ด้วยเครื่องหมายเปอร์เซ็นต์ (%) ตามด้วยตัวเลขฐานสิบหกสองหลัก นี่คือการเข้ารหัสที่อธิบายไว้ใน» RFC 3986 สำหรับการป้องกันตัวอักษรจากการถูกตีความว่าเป็นตัวคั่น URL พิเศษและเพื่อป้องกัน URL จากการถูกสื่อด้วยการส่งผ่านการแปลงอักขระ (เช่นระบบอีเมลบางระบบ)

หมายเหตุเกี่ยวกับ RFC 3986 vs 1738 rawurlencode ก่อน php 5.3 เข้ารหัสอักขระเครื่องหมายตัวหนอน ( ~) ตาม RFC 1738 อย่างไรก็ตาม PHP 5.3 นั้น rawurlencode ดังต่อไปนี้ RFC 3986 ซึ่งไม่จำเป็นต้องเข้ารหัสอักขระตัวหนอน

urlencodeเข้ารหัสช่องว่างเป็นเครื่องหมายบวก (ไม่เหมือน%20ที่ทำใน rawurlencode) (ดูhttp://us2.php.net/manual/en/function.urlencode.php )

ส่งคืนสตริงที่อักขระที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมดยกเว้น -_ ถูกแทนที่ด้วยเครื่องหมายเปอร์เซ็นต์ (%) ตามด้วยตัวเลขฐานสิบหกสองตัวและช่องว่างที่เข้ารหัสเป็นเครื่องหมายบวก (+) มันถูกเข้ารหัสในลักษณะเดียวกับที่ข้อมูลที่โพสต์จากรูปแบบ WWW นั้นถูกเข้ารหัสซึ่งเป็นวิธีเดียวกับในประเภทสื่อที่ใช้ / x-www-form-urlencoded สิ่งนี้แตกต่างจากการเข้ารหัส RFC 3986 (ดู rawurlencode ()) ในที่นั้นด้วยเหตุผลทางประวัติศาสตร์ช่องว่างจะถูกเข้ารหัสเป็นเครื่องหมายบวก (+)

สอดคล้องกับคำนิยามสำหรับโปรแกรมนี้ / x-www ฟอร์ม urlencoded ในRFC 1866

อ่านเพิ่มเติม:

นอกจากนี้คุณยังอาจต้องการที่จะดูการอภิปรายที่http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode

นอกจากนี้RFC 2396ยังมีค่าดู RFC 2396 กำหนดไวยากรณ์ URI ที่ถูกต้อง ส่วนหลักที่เราสนใจคือจาก 3.4 Query Component:

ภายในองค์ประกอบแบบสอบถามตัวละครจะถูกสงวนไว้";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"

อย่างที่คุณเห็น+เป็นอักขระที่สงวนไว้ในสตริงการสืบค้นและดังนั้นจึงจำเป็นต้องเข้ารหัสตาม RFC 3986 (เช่นเดียวกับ rawurlencode)


27
แล้วอันไหนล่ะ?
Gary Willoughby

79
rawurlencode ไปกับมาตรฐานในกรณีนี้ urlencode จะถูกเก็บไว้เพียงสำหรับการใช้งานแบบเดิม
โจนาธาน Fingland

2
ขอบคุณมากนั่นคือสิ่งที่ฉันคิดว่าฉันแค่ต้องการความเห็นที่สองก่อนที่ฉันจะเริ่มอัปเดตโค้ดจำนวนมาก
Gary Willoughby

3
ฉันคิดว่ามัน rawurlencode ที่ไม่ได้เข้ารหัสช่องว่างเป็นเครื่องหมายบวก แต่เป็น% 20s
BigName

2
@Pindatjuh: ส่วนที่คุณอ้างอิงข้อยกเว้นเดียวคือระบบเดิมซึ่งคาดว่าสตริงการสืบค้นจะเป็นไปตามรูปแบบการเข้ารหัสแบบฟอร์มของช่องว่างที่เข้ารหัสเป็น + แทน% 20 (ในกรณีที่คุณต้องการ urlencode)หมายความว่าในขณะที่ rawurlencode นั้นเหมาะสมกับสถานการณ์ส่วนใหญ่ บางระบบคาดว่าช่องว่างจะถูกเข้ารหัสเป็น + (เครื่องหมายบวก) สำหรับระบบดังกล่าว urlencode เป็นตัวเลือกที่ดีกว่า
Jonathan Fingland

213

พิสูจน์อยู่ในซอร์สโค้ดของ PHP

ฉันจะนำคุณเข้าสู่กระบวนการที่รวดเร็วในการค้นหาสิ่งเหล่านี้ด้วยตัวคุณเองในอนาคตเมื่อใดก็ตามที่คุณต้องการ อดทนกับฉันจะมีซอร์สโค้ด C มากมายที่คุณสามารถอ่านได้ (ฉันอธิบายได้) หากคุณต้องการที่จะแปรงขึ้นในบางส่วน C เป็นสถานที่ที่ดีที่จะเริ่มต้นคือวิกิพีเดีย

ดาวน์โหลดซอร์ส (หรือใช้http://lxr.php.net/เพื่อเรียกดูแบบออนไลน์), grep ไฟล์ทั้งหมดสำหรับชื่อฟังก์ชั่นคุณจะพบบางสิ่งเช่นนี้:

PHP 5.3.6 (ล่าสุดในขณะที่เขียน) อธิบายทั้งสองฟังก์ชั่นในรหัส C พื้นเมืองของพวกเขาในแฟ้มurl.c

RawUrlEncode ()

PHP_FUNCTION(rawurlencode)
{
    char *in_str, *out_str;
    int in_str_len, out_str_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
                              &in_str_len) == FAILURE) {
        return;
    }

    out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
    RETURN_STRINGL(out_str, out_str_len, 0);
}

urlencode ()

PHP_FUNCTION(urlencode)
{
    char *in_str, *out_str;
    int in_str_len, out_str_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
                              &in_str_len) == FAILURE) {
        return;
    }

    out_str = php_url_encode(in_str, in_str_len, &out_str_len);
    RETURN_STRINGL(out_str, out_str_len, 0);
}

ตกลงอะไรที่นี่แตกต่างกันอย่างไร

พวกเขาทั้งสองอยู่ในสาระสำคัญเรียกฟังก์ชั่นภายในที่แตกต่างกันสองตามลำดับ: php_raw_url_encodeและphp_url_encode

ไปหาฟังก์ชั่นเหล่านั้นกัน!

ให้ดูที่ php_raw_url_encode

PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
{
    register int x, y;
    unsigned char *str;

    str = (unsigned char *) safe_emalloc(3, len, 1);
    for (x = 0, y = 0; len--; x++, y++) {
        str[y] = (unsigned char) s[x];
#ifndef CHARSET_EBCDIC
        if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
            (str[y] < 'A' && str[y] > '9') ||
            (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
            (str[y] > 'z' && str[y] != '~')) {
            str[y++] = '%';
            str[y++] = hexchars[(unsigned char) s[x] >> 4];
            str[y] = hexchars[(unsigned char) s[x] & 15];
#else /*CHARSET_EBCDIC*/
        if (!isalnum(str[y]) && strchr("_-.~", str[y]) != NULL) {
            str[y++] = '%';
            str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
            str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
#endif /*CHARSET_EBCDIC*/
        }
    }
    str[y] = '\0';
    if (new_length) {
        *new_length = y;
    }
    return ((char *) str);
}

และแน่นอน php_url_encode:

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
{
    register unsigned char c;
    unsigned char *to, *start;
    unsigned char const *from, *end;

    from = (unsigned char *)s;
    end = (unsigned char *)s + len;
    start = to = (unsigned char *) safe_emalloc(3, len, 1);

    while (from < end) {
        c = *from++;

        if (c == ' ') {
            *to++ = '+';
#ifndef CHARSET_EBCDIC
        } else if ((c < '0' && c != '-' && c != '.') ||
                   (c < 'A' && c > '9') ||
                   (c > 'Z' && c < 'a' && c != '_') ||
                   (c > 'z')) {
            to[0] = '%';
            to[1] = hexchars[c >> 4];
            to[2] = hexchars[c & 15];
            to += 3;
#else /*CHARSET_EBCDIC*/
        } else if (!isalnum(c) && strchr("_-.", c) == NULL) {
            /* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
            to[0] = '%';
            to[1] = hexchars[os_toascii[c] >> 4];
            to[2] = hexchars[os_toascii[c] & 15];
            to += 3;
#endif /*CHARSET_EBCDIC*/
        } else {
            *to++ = c;
        }
    }
    *to = 0;
    if (new_length) {
        *new_length = to - start;
    }
    return (char *) start;
}

หนึ่งความรู้เล็กน้อยก่อนที่ฉันจะก้าวไปข้างหน้าEBCDIC เป็นชุดอักขระอื่นคล้ายกับ ASCII แต่เป็นคู่แข่งทั้งหมด PHP พยายามจัดการกับทั้งคู่ แต่โดยทั่วไปหมายถึงนี้ไบต์ไบต์ 0x4c EBCDIC ไม่ได้เป็นLใน ASCII <ก็จริง ฉันแน่ใจว่าคุณเห็นความสับสนที่นี่

ฟังก์ชั่นทั้งสองนี้จัดการ EBCDIC หากเว็บเซิร์ฟเวอร์ได้กำหนดไว้

นอกจากนี้พวกเขาทั้งสองใช้อาร์เรย์ของตัวอักษร (คิดว่าประเภทสตริง) hexcharsค้นหาเพื่อรับค่าบางอย่างอาร์เรย์มีการอธิบายดังนี้:

/* rfc1738:

   ...The characters ";",
   "/", "?", ":", "@", "=" and "&" are the characters which may be
   reserved for special meaning within a scheme...

   ...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
   reserved characters used for their reserved purposes may be used
   unencoded within a URL...

   For added safety, we only leave -_. unencoded.
 */

static unsigned char hexchars[] = "0123456789ABCDEF";

นอกเหนือจากนั้นฟังก์ชั่นนั้นแตกต่างกันมากและฉันจะอธิบายมันใน ASCII และ EBCDIC

ความแตกต่างใน ASCII:

urlencode:

  • คำนวณความยาวเริ่มต้น / สิ้นสุดของสตริงอินพุตจัดสรรหน่วยความจำ
  • เดินผ่าน while-loop เพิ่มขึ้นจนกว่าเราจะถึงจุดสิ้นสุดของสตริง
  • คว้าตัวละครปัจจุบัน
  • หากตัวละครมีค่าเท่ากับ ASCII Char 0x20 (เช่น "ช่องว่าง") ให้เพิ่ม+เครื่องหมายลงในสตริงเอาต์พุต
  • ถ้ามันไม่ได้เป็นช่องว่างและก็ยังไม่ได้ตัวเลข ( isalnum(c)) และยังไม่ได้และ_, -หรือ.ตัวละครแล้วเราเอาท์พุท%สัญญาณไปยังตำแหน่งอาร์เรย์ 0, ทำดูอาร์เรย์ขึ้นไปhexcharsอาร์เรย์สำหรับการค้นหาสำหรับos_toasciiอาร์เรย์ ( อาเรย์จากอาปาเช่ที่แปลอักขระชาร์ตเป็นเลขฐานสิบหก) สำหรับคีย์ของc(ตัวละครปัจจุบัน) จากนั้นเราเลื่อนบิตทริกซ์ไปทางขวา 4 กำหนดค่านั้นให้กับตัวละคร 1 และตำแหน่งที่ 2 เรากำหนดการค้นหาเดียวกัน ตรรกะและเพื่อดูว่าค่าเป็น 15 (0xF) และส่งกลับ 1 ในกรณีนั้นหรือ 0 เป็นอย่างอื่น ในตอนท้ายคุณจะได้สิ่งที่เข้ารหัส
  • ถ้ามันไม่ใช่ช่องว่างมันก็เป็นตัวอักษรและตัวเลขหรือหนึ่งใน_-.ตัวอักษรมันจะแสดงผลลัพธ์ออกมาอย่างแน่นอน

RAWURLENCODE:

  • จัดสรรหน่วยความจำสำหรับสตริง
  • วนซ้ำตามความยาวที่ระบุในการเรียกใช้ฟังก์ชัน (ไม่คำนวณในฟังก์ชั่นเช่นเดียวกับ URLENCODE)

หมายเหตุ:โปรแกรมเมอร์จำนวนมากอาจจะไม่เคยเห็นสำหรับวงสำทับด้วยวิธีนี้จะค่อนข้าง hackish และไม่ประชุมมาตรฐานที่ใช้กับที่สุดสำหรับลูปให้ความสนใจก็กำหนดxและyตรวจสอบสำหรับทางออกในlenการเข้าถึง 0, และการเพิ่มขึ้นทั้งในและx yฉันรู้ว่าไม่ใช่สิ่งที่คุณคาดหวัง แต่เป็นรหัสที่ถูกต้อง

  • strกำหนดตัวละครในปัจจุบันไปยังตำแหน่งที่ตรงกันในตัวละคร
  • มันตรวจสอบว่าตัวละครปัจจุบันเป็นตัวอักษรและตัวเลขหรือหนึ่งใน_-.ตัวอักษรและถ้ามันไม่ได้เราทำเกือบจะได้รับมอบหมายเช่นเดียวกับ URLENCODE ที่มัน preforms การค้นหา แต่เราเพิ่มขึ้นแตกต่างกันใช้y++มากกว่าto[1]เพราะนี่คือ สตริงจะถูกสร้างขึ้นในรูปแบบที่แตกต่างกัน แต่ไปถึงเป้าหมายเดียวกันในตอนท้าย
  • เมื่อการวนซ้ำเสร็จสิ้นและความยาวหายไปจริง ๆ แล้วจะเป็นการยกเลิกสตริงการกำหนด\0ไบต์
  • มันจะส่งกลับสตริงที่เข้ารหัส

แตกต่าง:

  • UrlEncode ตรวจสอบพื้นที่กำหนดสัญญาณ + RawURLEncode ไม่ได้
  • UrlEncode ไม่ได้กำหนด\0ไบต์ให้กับสตริง RawUrlEncode ทำ (ซึ่งอาจเป็นจุดที่สงสัย)
  • พวกมันย้ำไม่ต่างกันใครมีแนวโน้มที่จะล้นด้วยสตริงที่มีรูปแบบไม่ถูกต้องฉันแค่แนะนำสิ่งนี้และฉันยังไม่ได้ตรวจสอบจริง

โดยทั่วไปแล้วจะมีการทำซ้ำต่างกันหนึ่งจะกำหนดเครื่องหมาย + ในกรณีที่ ASCII 20

ความแตกต่างใน EBCDIC:

urlencode:

  • ตั้งค่าการวนซ้ำเช่นเดียวกับ ASCII
  • ยังคงแปลอักขระ "ช่องว่าง" เป็นเครื่องหมาย + หมายเหตุ - ฉันคิดว่าสิ่งนี้จะต้องรวบรวมใน EBCDIC หรือคุณจะจบลงด้วยข้อผิดพลาด? ใครสามารถแก้ไขและยืนยันสิ่งนี้ได้?
  • มันตรวจสอบถ้าถ่านปัจจุบันเป็นถ่านก่อนที่จะ0มีข้อยกเว้นของการเป็นที่.หรือ-, หรือน้อยกว่าAแต่มากกว่าถ่าน9, หรือมากกว่าZและน้อยกว่าแต่ไม่ได้เป็นa หรือดีกว่า(ใช่ EBCDIC เป็นระเบียบเพื่อทำงานกับ) หากตรงกับสิ่งใด ๆ ให้ทำการค้นหาที่คล้ายกันที่พบในเวอร์ชัน ASCII (ไม่ต้องค้นหาใน os_toascii)_z

RAWURLENCODE:

  • ตั้งค่าการวนซ้ำเช่นเดียวกับ ASCII
  • การตรวจสอบเช่นเดียวกับที่อธิบายไว้ในการเข้ารหัส URL ของ EBCDIC รุ่นยกเว้นว่าถ้ามากกว่าzนั้นจะแยก~ออกจากการเข้ารหัส URL
  • การกำหนดเช่นเดียวกับ ASCII RawUrlEncode
  • ยังคงต่อท้าย\0ไบต์กับสตริงก่อนส่งคืน

บทสรุปที่ยิ่งใหญ่

  • ทั้งคู่ใช้ตารางค้นหา hexchars เดียวกัน
  • URIEncode ไม่ได้ยกเลิกสตริงด้วย \ 0, raw ทำ
  • หากคุณกำลังทำงานใน EBCDIC ฉันขอแนะนำให้ใช้ RawUrlEncode เนื่องจากจัดการ~UrlEncode นั้นไม่ได้ ( นี่เป็นปัญหาที่รายงาน ) เป็นที่น่าสังเกตว่า ASCII และ EBCDIC 0x20 เป็นช่องว่างทั้งคู่
  • พวกมันซ้ำกันอย่างใดอย่างหนึ่งอาจเร็วกว่าหนึ่งอาจมีแนวโน้มที่หน่วยความจำหรือการใช้ประโยชน์จากสตริง
  • URIEncode ทำให้มีช่องว่างใน+RawUrlEncode ทำให้มีช่องว่าง%20ผ่านการค้นหาอาร์เรย์

คำเตือน:ฉันไม่ได้สัมผัส C เป็นเวลาหลายปีและฉันไม่ได้ดู EBCDIC ในเวลานานมาก หากฉันผิดที่ไหนสักแห่งให้ฉันรู้

การใช้งานที่แนะนำ

rawurlencode เป็นวิธีที่ใช้เวลาส่วนใหญ่ตามทั้งหมดนี้ อย่างที่คุณเห็นในคำตอบของโจนาธานฟิงแลนด์ติดอยู่กับมันในกรณีส่วนใหญ่ มันเกี่ยวข้องกับรูปแบบที่ทันสมัยสำหรับส่วนประกอบ URI ซึ่ง urlencode ทำสิ่งต่าง ๆ ในแบบโรงเรียนเก่าโดยที่ + หมายถึง "space"

หากคุณพยายามแปลงระหว่างรูปแบบเก่าและรูปแบบใหม่ตรวจสอบให้แน่ใจว่ารหัสของคุณไม่ผิดพลาดและเปลี่ยนสิ่งที่เป็นการถอดรหัส + ลงชื่อเข้าช่องว่างด้วยการเข้ารหัสสองครั้งโดยบังเอิญหรือสถานการณ์ "oops" ที่คล้ายกันรอบ ๆ นี้ พื้นที่ / ปัญหา 20% / +

หากคุณกำลังทำงานกับระบบเก่าที่มีซอฟต์แวร์รุ่นเก่าที่ไม่ชอบรูปแบบใหม่ติดกับ urlencode แต่ฉันเชื่อว่า% 20 จะสามารถใช้งานได้แบบย้อนกลับได้จริง ๆ เพราะทำงานภายใต้มาตรฐาน% 20 เก่าแล้ว แนะนำ ให้มันยิงถ้าคุณพร้อมสำหรับการเล่นรอบแจ้งให้เราทราบว่ามันทำงานออกมาสำหรับคุณ

โดยพื้นฐานแล้วคุณควรใช้ข้อมูลดิบยกเว้นว่าระบบ EBCDIC ของคุณจะเกลียดคุณจริงๆ โปรแกรมเมอร์ส่วนใหญ่จะไม่เคยพบกับ EBCDIC ในระบบใด ๆ ที่เกิดขึ้นหลังจากปี 2000 อาจจะถึงปี 1990 (นั่นคือการผลักดัน


ฉันไม่เคยกังวลเกี่ยวกับการเข้ารหัสสองครั้งหลังจากทั้งหมดฉันควรรู้ว่าฉันได้เข้ารหัสอะไรเพราะฉันกำลังทำการเข้ารหัสฉันคิดว่า ตั้งแต่ฉันถอดรหัสทุกอย่างที่ฉันได้รับด้วยโหมดความเข้ากันได้ซึ่งรู้วิธีการรักษา + สำหรับพื้นที่ฉันมีเท่ากันไม่เคยเจอปัญหาที่คุณพยายามเตือนเกี่ยวกับที่นี่ ฉันสามารถเข้าใจแหล่งที่มาหากเราไม่ทราบว่ามีอะไรทำ แต่สิ่งที่เราเรียนรู้ที่นี่ว่าเราไม่ได้รู้จากการดำเนินการทั้งสองฟังก์ชั่น ฉันรู้ว่าฉันลำเอียง แต่ฉันก็อดไม่ได้ที่จะคิดว่าสิ่งนี้เป็นไปได้ยาก ความรุ่งโรจน์ในความพยายามแม้ว่า! =)
nickl-

2
+1 สำหรับส่วนนี้: "ฉันเชื่อว่า% 20 จะเข้ากันได้จริง ๆ ตามที่ทำงานภายใต้มาตรฐานเดิม% 20 ไม่เป็นที่ต้องการ"
Gras Double

3
คำตอบที่ดี แต่อาจ overkill เล็กน้อย?
rinogo

38
echo rawurlencode('http://www.google.com/index.html?id=asd asd');

อัตราผลตอบแทน

http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd%20asd

ในขณะที่

echo urlencode('http://www.google.com/index.html?id=asd asd');

อัตราผลตอบแทน

http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd+asd

ความแตกต่างคือการasd%20asdเทียบกับasd+asd

urlencode แตกต่างจาก RFC 1738 โดยการเข้ารหัสช่องว่าง+แทน%20


28

เหตุผลหนึ่งที่ใช้งานได้จริงในการเลือกข้อหนึ่งคือถ้าคุณจะใช้ผลลัพธ์ในสภาพแวดล้อมอื่นเช่น JavaScript

ใน PHP urlencode('test 1')จะส่งคืน'test+1'ขณะที่rawurlencode('test 1')ส่งคืน'test%201'ผลลัพธ์

แต่ถ้าคุณต้องการ "ถอดรหัส" สิ่งนี้ใน JavaScript โดยใช้ฟังก์ชัน decodeURI ()จากนั้นdecodeURI("test+1")จะให้คุณ"test+1"ในขณะที่decodeURI("test%201")จะให้"test 1"ผลลัพธ์

กล่าวอีกนัยหนึ่งช่องว่าง ("") ที่เข้ารหัสโดยurlencodeเป็นบวก ("+") ใน PHP จะไม่ถูกถอดรหัสอย่างถูกต้องโดยdecodeURIใน JavaScript

ในกรณีเช่นนี้ฟังก์ชันrawurlencode PHP ควรใช้


6
นี่คือคำตอบที่ดีที่สุดที่ฉันเคยเห็น มันมีข้อเสนอแนะสำหรับการใช้งานโดยตัวอย่างจริงของโลก นอกจากนี้ยังกระชับ
dotancohen

มันเป็นตัวอย่างที่ดีแม้ว่าฉันจะชอบjson_encodeและJSON.parseจุดประสงค์นั้น
FabrícioMatté

21

ฉันเชื่อว่าช่องว่างต้องเข้ารหัสเป็น:

ตัวอย่างต่อไปนี้แสดงการใช้งานที่ถูกต้องrawurlencodeและurlencode:

echo "http://example.com"
    . "/category/" . rawurlencode("latest songs")
    . "/search?q=" . urlencode("lady gaga");

เอาท์พุท:

http://example.com/category/latest%20songs/search?q=lady+gaga

จะเกิดอะไรขึ้นถ้าคุณเข้ารหัสเส้นทางและส่วนประกอบของสตริงข้อความในทางกลับกัน สำหรับตัวอย่างต่อไปนี้:

http://example.com/category/latest+songs/search?q=lady%20gaga
  • เว็บเซิร์ฟเวอร์จะค้นหาไดเรกทอรีlatest+songsแทนlatest songs
  • พารามิเตอร์สตริงแบบสอบถามqจะมีlady gaga

2
"พารามิเตอร์สตริงข้อความค้นหาqจะมีlady gaga" มีอะไรอีกบ้างในนั้น? qดูเหมือนว่าพารามิเตอร์การสืบค้นมีค่าเดียวกันส่งผ่านไปยัง$_GETอาร์เรย์โดยไม่คำนึงถึงการใช้rawurlencodeหรือurlencodeใน PHP 5.2+ แม้ว่าการurlencodeเข้ารหัสในapplication/x-www-form-urlencodedรูปแบบที่เป็นค่าเริ่มต้นสำหรับคำขอ GET ดังนั้นฉันจะไปกับแนวทางของคุณ +1
FabrícioMatté

2
ฉันต้องการชี้แจงว่าทั้งสอง+และ%20ถอดรหัสเป็นพื้นที่เมื่อใช้ในสตริงการสืบค้น
Salman

5

ความแตกต่างอยู่ในค่าตอบแทนคือ:

urlencode () :

ส่งคืนสตริงที่อักขระที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมดยกเว้น -_ ถูกแทนที่ด้วยเครื่องหมายเปอร์เซ็นต์ (%) ตามด้วยตัวเลขฐานสิบหกสองตัวและช่องว่างที่เข้ารหัสเป็นเครื่องหมายบวก (+) มันถูกเข้ารหัสในลักษณะเดียวกับที่ข้อมูลที่โพสต์จากรูปแบบ WWW นั้นถูกเข้ารหัสซึ่งเป็นวิธีเดียวกับในประเภทสื่อที่ใช้ / x-www-form-urlencoded สิ่งนี้แตกต่างจากการเข้ารหัส RFC 1738 (ดู rawurlencode ()) ในที่นั้นด้วยเหตุผลทางประวัติศาสตร์ช่องว่างจะถูกเข้ารหัสเป็นเครื่องหมายบวก (+)

rawurlencode () :

ส่งคืนสตริงที่อักขระที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมดยกเว้น -_ ถูกแทนที่ด้วยเครื่องหมายเปอร์เซ็นต์ (%) แล้วตามด้วยเลขฐานสิบหกสองหลัก นี่คือการเข้ารหัสที่อธิบายไว้ใน» RFC 1738 สำหรับการป้องกันตัวอักษรจากการถูกตีความเป็นตัวคั่น URL พิเศษและเพื่อป้องกัน URL จากการถูกสื่อด้วยการส่งผ่านการแปลงอักขระ (เช่นระบบอีเมลบางระบบ)

ทั้งสองมีความคล้ายกันมาก แต่หลัง (rawurlencode) จะแทนที่ช่องว่างด้วย '%' และเลขฐานสิบหกสองหลักซึ่งเหมาะสำหรับการเข้ารหัสรหัสผ่านหรือเช่นที่ '+' ไม่เช่น:

echo '<a href="ftp://user:', rawurlencode('foo @+%/'),
     '@ftp.example.com/x.txt">';
//Outputs <a href="ftp://user:foo%20%40%2B%25%2F@ftp.example.com/x.txt">

2
OP ถามว่าจะรู้ได้อย่างไรว่าควรใช้อะไรและเมื่อใด การรู้ว่าแต่ละอันทำอะไรกับช่องว่างไม่ช่วยให้ OP ตัดสินใจได้ถ้าเขาไม่รู้ความสำคัญของค่าตอบแทนที่ต่างกัน
dotancohen

5

1. อะไรคือความแตกต่างและ

ความแตกต่างเพียงอย่างเดียวคือวิธีที่ได้รับการปฏิบัติในพื้นที่

urlencode - ขึ้นอยู่กับการใช้งานแบบดั้งเดิมแปลงช่องว่างเป็น +

rawurlencode - ตามRFC 1738แปลช่องว่างเป็น% 20

สาเหตุของความแตกต่างคือเนื่องจาก + ถูกจองและถูกต้อง (ไม่ได้เข้ารหัส) ใน URL

2. ข้อไหนดี?

ฉันอยากจะเห็นเหตุผลบางอย่างสำหรับการเลือกหนึ่งมากกว่าอื่น ๆ ... ฉันต้องการที่จะสามารถเลือกหนึ่งและใช้มันตลอดไปด้วยความยุ่งยากน้อยที่สุด

ยุติธรรมพอฉันมีกลยุทธ์ง่ายๆที่ฉันติดตามเมื่อทำการตัดสินใจเหล่านี้ซึ่งฉันจะแบ่งปันกับคุณด้วยความหวังว่ามันจะช่วยได้

ฉันคิดว่าเป็นข้อกำหนด HTTP / 1.1 RFC 2616ซึ่งเรียกว่า" แอปพลิเคชันที่ทนทาน "

ลูกค้าควรมีความอดทนในการแยกวิเคราะห์ Status-Line และเซิร์ฟเวอร์ทนเมื่อแยกวิเคราะห์ Request-Line

เมื่อต้องเผชิญกับคำถามเช่นนี้กลยุทธ์ที่ดีที่สุดคือการบริโภคให้ได้มากที่สุดและผลิตตามมาตรฐาน

ดังนั้นคำแนะนำของฉันคือใช้rawurlencodeในการผลิตสตริงที่เข้ารหัสตามมาตรฐาน RFC 1738 และใช้urldecodeเพื่อให้เข้ากันได้แบบย้อนหลังและรองรับทุกสิ่งที่คุณอาจเจอเพื่อบริโภค

ตอนนี้คุณสามารถใช้คำของฉันมัน แต่ให้เราพิสูจน์ ...

php > $url = <<<'EOD'
<<< > "Which, % of Alice's tasks saw $s @ earnings?"
<<< > EOD;
php > echo $url, PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > echo urlencode($url), PHP_EOL;
%22Which%2C+%25+of+Alice%27s+tasks+saw+%24s+%40+earnings%3F%22
php > echo rawurlencode($url), PHP_EOL;
%22Which%2C%20%25%20of%20Alice%27s%20tasks%20saw%20%24s%20%40%20earnings%3F%22
php > echo rawurldecode(urlencode($url)), PHP_EOL;
"Which,+%+of+Alice's+tasks+saw+$s+@+earnings?"
php > // oops that's not right???
php > echo urldecode(rawurlencode($url)), PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > // now that's more like it

ดูเหมือนว่า PHP มีสิ่งนี้อยู่ในใจแม้ว่าฉันจะไม่เคยเจอใครที่ปฏิเสธทั้งสองรูปแบบ แต่ฉันคิดว่ากลยุทธ์ที่ดีกว่าที่จะนำมาใช้เป็นกลยุทธ์ defacto ของคุณได้ไหม

Njoy!


4

urlencode : สิ่งนี้แตกต่างจากการเข้ารหัส» RFC 1738 (ดู rawurlencode ()) ด้วยเหตุผลทางประวัติศาสตร์ช่องว่างจะถูกเข้ารหัสเป็นเครื่องหมายบวก (+)


2

ช่องว่างที่เข้ารหัสเมื่อ%20เทียบกับ+

เหตุผลที่ดีที่สุดที่ฉันเคยเห็นในการใช้งานrawurlencode()ในกรณีส่วนใหญ่เป็นเพราะurlencodeเข้ารหัสพื้นที่ข้อความเป็น+(เครื่องหมายบวก) ที่rawurlencodeเข้ารหัสพวกเขาเป็นที่เห็นบ่อย%20:

echo urlencode("red shirt");
// red+shirt

echo rawurlencode("red shirt");
// red%20shirt

ฉันเห็นจุดสิ้นสุด API เฉพาะบางอย่างที่ยอมรับข้อความค้นหาที่เข้ารหัสแล้วซึ่งคาดว่าจะเห็น%20ช่องว่างและด้วยเหตุนี้จึงล้มเหลวหากมีการใช้เครื่องหมายบวกแทน เห็นได้ชัดว่าสิ่งนี้จะแตกต่างระหว่างการใช้งาน API และระยะทางของคุณอาจแตกต่างกันไป


1

ฉันเชื่อว่า urlencode ใช้สำหรับพารามิเตอร์การสืบค้นในขณะที่ rawurlencode มีไว้สำหรับส่วนของเส้นทาง นี่เป็นสาเหตุหลักมาจาก%20สำหรับส่วนของเส้นทางเทียบ+กับพารามิเตอร์การสืบค้น ดูคำตอบที่พูดถึงช่องว่าง: เมื่อใดที่เข้ารหัสพื้นที่เป็นบวก (+) หรือ% 20

อย่างไรก็ตาม%20ตอนนี้ทำงานในพารามิเตอร์การสืบค้นด้วยเช่นกันซึ่งเป็นเหตุผลที่ rawurlencode ปลอดภัยกว่าเสมอ อย่างไรก็ตามเครื่องหมายบวกมีแนวโน้มที่จะใช้เมื่อประสบการณ์ของผู้ใช้ในการแก้ไขและความสามารถในการอ่านของพารามิเตอร์คิวรีมีความสำคัญ

โปรดทราบว่าวิธีการนี้rawurldecodeไม่ได้ถอดรหัส+ลงในช่องว่าง ( http://au2.php.net/manual/en/function.rawurldecode.php ) นี่คือเหตุผลว่าทำไม $ _GET จึงถูกส่งผ่านโดยอัตโนมัติเสมอurldecodeซึ่งหมายความว่า+และ%20ทั้งสองจะถูกถอดรหัสลงในช่องว่าง

หากคุณต้องการให้การเข้ารหัสและถอดรหัสสอดคล้องกันระหว่างอินพุตและเอาต์พุตและคุณได้เลือกที่จะใช้+และไม่%20ใช้พารามิเตอร์การสืบค้นเสมอดังนั้นจึงurlencodeเป็นสิ่งที่ดีสำหรับพารามิเตอร์คิวรี (คีย์และค่า)

บทสรุปคือ:

ส่วนเส้นทาง - ใช้ rawurlencode / rawurldecode เสมอ

พารามิเตอร์การสืบค้น - สำหรับการถอดรหัสจะใช้ urldecode (ทำโดยอัตโนมัติ) เสมอสำหรับการเข้ารหัสทั้ง rawurlencode หรือ urlencode นั้นใช้ได้เพียงแค่เลือกหนึ่งตัวเพื่อให้สอดคล้องกันโดยเฉพาะเมื่อเปรียบเทียบ URL


0

simple * rawurlencode the path - path เป็นส่วนหนึ่งของ "?" - ช่องว่างจะต้องเข้ารหัสเป็น% 20 * urlencode ของสตริงข้อความค้นหา - สตริงข้อความค้นหาเป็นส่วนหลัง "?" พื้นที่มีการเข้ารหัสที่ดีขึ้นเป็น "+" = rawurlencode เข้ากันได้โดยทั่วไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.