변수를 사용하여 URL을 만들려면 문자열을 인코딩하는 두 가지 선택이 있습니다. urlencode()
그리고 rawurlencode()
.
차이점은 무엇이며 어떤 것이 선호됩니까?
rawurlencode
. 로 인코딩 된 공간이 주어질 때 질식하는 시스템을 거의 사용하지 않는 %20
반면, 인코딩 된 공간 +
을 더 일반적으로 인코딩 하는 시스템은 거의 사용하지 않습니다 .
변수를 사용하여 URL을 만들려면 문자열을 인코딩하는 두 가지 선택이 있습니다. urlencode()
그리고 rawurlencode()
.
차이점은 무엇이며 어떤 것이 선호됩니까?
rawurlencode
. 로 인코딩 된 공간이 주어질 때 질식하는 시스템을 거의 사용하지 않는 %20
반면, 인코딩 된 공간 +
을 더 일반적으로 인코딩 하는 시스템은 거의 사용하지 않습니다 .
답변:
그것은 당신의 목적에 달려 있습니다. 다른 시스템과의 상호 운용성이 중요하다면 rawurlencode가 좋은 방법입니다. 한 가지 예외는 쿼리 문자열이 % 20 대신 +로 인코딩 된 형식의 공백을 양식 인코딩 스타일을 따르는 것으로 예상하는 레거시 시스템입니다 (이 경우 urlencode가 필요함).
rawurlencode 는 PHP 5.3.0 및 RFC 3986 이전의 RFC 1738을 따릅니다 ( http://us2.php.net/manual/en/function.rawurlencode.php 참조 ).
-_. ~를 제외한 모든 영숫자가 아닌 문자가 백분율 (%) 부호로 대체되고 두 개의 16 진 숫자가있는 문자열을 리턴합니다. 이것은 리터럴 문자가 특수 URL 분리 문자로 해석되지 않도록 보호하고 문자 변환 (일부 이메일 시스템과 같은)을 사용하여 전송 매체에 의해 URL이 엉망이되는 것을 방지하기 위해»RFC 3986에 설명 된 인코딩입니다.
php 5.3 이전의 rawurlencode ~
는 RFC 1738에 따라 물결표 문자 ( )를 인코딩했습니다 . 그러나 PHP 5.3에서 rawurlencode는 물결표 문자 인코딩이 필요하지 않은 RFC 3986을 따릅니다.
urlencode 는 공백을 더하기 부호로 인코딩합니다 ( %20
rawurlencode 에서와는 달리 ) ( http://us2.php.net/manual/en/function.urlencode.php 참조 )
영숫자가 아닌 모든 문자가 -_을 제외한 문자열을 반환합니다. 는 퍼센트 (%) 기호와 두 개의 16 진수 및 플러스 (+) 기호로 인코딩 된 공백으로 대체되었습니다. WWW 양식에서 게시 된 데이터가 인코딩되는 방식과 동일한 방식으로 인코딩됩니다. 이는 application / x-www-form-urlencoded 미디어 유형과 동일한 방식입니다. 이것은 역사적 이유로 공백이 더하기 (+) 부호로 인코딩된다는 점에서»RFC 3986 인코딩 (rawurlencode () 참조)과 다릅니다.
이는 RFC 1866의 application / x-www-form-urlencoded에 대한 정의에 해당합니다 .
추가 자료 :
http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode 에서 토론을 볼 수도 있습니다 .
또한 RFC 2396 을 살펴볼 가치가 있습니다. RFC 2396은 유효한 URI 구문을 정의합니다. 우리가 관심을 갖는 주요 부분은 3.4 쿼리 구성 요소입니다.
쿼리 구성 요소 내에서 문자 가 예약됩니다.
";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"
보시다시피 +
쿼리 문자열에 예약 문자가 있으므로 RFC 3986에 따라 (rawurlencode에서와 같이) 인코딩해야합니다.
증명은 PHP의 소스 코드에 있습니다.
앞으로 언제든지 원하는대로 이러한 종류의 정보를 찾는 방법에 대한 빠른 프로세스를 안내합니다. 저와 함께, 당신이 훑어 볼 수있는 많은 C 소스 코드가있을 것입니다 (나는 그것을 설명합니다). 일부 C를 마무리하려면 SO wiki를 시작하는 것이 좋습니다 .
소스를 다운로드하거나 ( http://lxr.php.net/ 을 사용 하여 온라인으로 탐색) 함수 이름의 모든 파일을 grep하면 다음과 같은 것을 찾을 수 있습니다.
PHP 5.3.6 (가장 최근 작성 당시)은 url.c 파일에서 네이티브 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
그런 기능들을 찾으십시오!
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);
}
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는 두 가지 모두를 처리하려고 시도합니다. 그러나 기본적으로 이것은 바이트 EBCDIC 0x4c 바이트가 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으로 설명하겠습니다.
URLENCODE :
+
출력 문자열에 부호를 추가하십시오 .isalnum(c)
도), 그리고되지 않으며 _
, -
또는 .
문자, 그때 우리는, 출력 %
배열 위치 0에 기호의에 배열 모양을 수행 hexchars
하기위한 조회에 배열 os_toascii
배열 ( (현재 문자) 의 키에 대해 Apache 에서 char을 16 진 코드로 변환 하는 배열 인 경우 c
, 우리는 비트를 4 씩 오른쪽으로 시프트하고 해당 값을 문자 1에 할당하고 위치 2에 동일한 조회를 지정합니다. 논리적이고 값이 15 (0xF)인지 확인하고이 경우 1을 반환하고 그렇지 않으면 0을 반환합니다. 결국에는 인코딩 된 것으로 끝납니다._-.
문자 중 하나이며 정확히 그대로 출력됩니다.RAWURLENCODE :
참고 : 많은 프로그래머는 아마 루프으로 반복이 방법을, 그것은 다소 hackish입니다 본 적이 아닌 표준 규칙은, 관심을 지불-루프, 그것은 할당 대부분의 사용 x
과 y
에, 종료에 대한 검사를 len
0에 도달하고, 단위 모두 x
와 y
. 나는 그것이 당신이 기대하는 것이 아니라 유효한 코드라는 것을 알고 있습니다.
str
._-.
문자 중 하나 인지 확인하고 그렇지 않은 경우 URLENCODE와 거의 동일한 할당을 수행하지만 조회를 수행 할 때는을 사용 y++
하지 않고 다르게 증가 to[1]
합니다. 현은 다른 방식으로 건축되고 있지만 어쨌든 같은 목표에 도달합니다.\0
바이트를 할당합니다 .차이점 :
\0
문자열에 바이트를 할당하지 않고 RawUrlEncode는 바이트를 할당합니다.기본적으로 다르게 반복됩니다. ASCII 20의 경우 + 기호가 할당됩니다.
URLENCODE :
0
있는 Being을 제외 .
하거나 -
, OR 미만 A
이지만보다 숯 9
, OR 보다 크를 Z
이하와 a
아니지만 _
. 또는 보다 큽니다 z
(예, EBCDIC는 약간 엉망입니다). 그 중 하나와 일치하면 ASCII 버전에서와 비슷한 검색을 수행하십시오 (os_toascii에서 검색하지 않아도 됨).RAWURLENCODE :
z
, 보다 크면 ~
URL 인코딩에서 제외됩니다 .\0
반환하기 전에 문자열에 바이트를 계속 추가합니다 .~
UrlEncode가 관리 하지 않기 때문입니다 ( 보고 된 문제 ). ASCII와 EBCDIC 0x20은 모두 공백입니다.+
만들고 RawUrlEncode는 %20
배열 조회 를 통해 공간을 만듭니다 .면책 조항 : 몇 년 동안 C를 만지지 않았으며 실제로 오랫동안 EBCDIC을 보지 못했습니다. 어딘가에 틀렸다면 알려주십시오.
이 모든 것을 바탕으로 rawurlencode는 대부분의 시간을가는 길입니다. Jonathan Fingland의 답변에서 볼 수 있듯이 대부분의 경우에 충실하십시오. urlencode가 구식 방식으로 +를 "공간"으로 사용하는 URI 구성 요소에 대한 최신 체계를 처리합니다.
이전 형식과 새 형식을 변환하려는 경우 코드가 손상되지 않도록 확인하고 실수로 이중 인코딩 또는 이와 유사한 "oops"시나리오를 통해 디코딩 된 + 부호가있는 것을 공백으로 바꾸십시오. 공간 / 20 % / + 문제.
새로운 형식을 선호하지 않는 구형 소프트웨어로 구형 시스템에서 작업하는 경우 urlencode를 사용하십시오. 그러나 이전 표준 % 20에서 작동했던 것처럼 % 20은 실제로 이전 버전과 호환됩니다. 선호합니다. 당신이 놀러 다니면 기회를주십시오. 어떻게 당신을 위해 일했는지 알려주십시오.
EBCDIC 시스템이 실제로 당신을 미워하지 않는 한 기본적으로, 당신은 날 것으로 고수해야합니다. 대부분의 프로그래머는 2000 년 이후, 심지어 1990 년 이후에 만들어진 시스템에서 EBCDIC를 절대로 사용하지 않을 것입니다.
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
다른 환경에서 하나를 선택해야하는 실질적인 이유 중 하나는 다른 환경 (예 : JavaScript)에서 결과를 사용하려는 경우입니다.
PHP에서는 결과가 urlencode('test 1')
반환 'test+1'
되는 동안 rawurlencode('test 1')
반환합니다 'test%201'
.
당신이 "디코드"필요하지만 자바 스크립트에서이 사용 decodeURI () 다음 기능을 decodeURI("test+1")
당신을 줄 것이다 "test+1"
동안 decodeURI("test%201")
당신을 줄 것이다 "test 1"
결과로.
다시 말해, PHP에서 urlencode 에 의해 플러스 ( "+")로 인코딩 된 공백 ( "") 은 JavaScript의 decodeURI 에 의해 올바르게 디코딩되지 않습니다 .
이러한 경우 rawurlencode PHP 함수를 사용해야합니다.
json_encode
그리고 JSON.parse
그 목적을 위해.
공백은 다음과 같이 인코딩되어야한다고 생각합니다.
%20
URL 경로 구성 요소 내에서 사용될 때+
URL 쿼리 문자열 구성 요소 또는 양식 데이터 내에서 사용되는 경우 ( 17.13.4 양식 내용 유형 참조 )다음 예는 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
q
에는 lady gaga
"다른 것이 포함되어 있습니까? 쿼리 매개 변수 q
는 PHP 5.2+ $_GET
를 사용 rawurlencode
하거나 사용하지 않고 동일한 값을 배열에 전달한 것으로 보입니다 urlencode
. 그래도 GET 요청의 기본 형식으로 urlencode
인코딩 application/x-www-form-urlencoded
하므로 귀하의 접근 방식을 사용합니다. +1
+
및 %20
쿼리 문자열에 사용하면 공간으로 디코딩된다.
차이점은 반환 값에 있습니다.
영숫자가 아닌 모든 문자가 -_을 제외한 문자열을 반환합니다. 는 퍼센트 (%) 기호와 두 개의 16 진수 및 플러스 (+) 기호로 인코딩 된 공백으로 대체되었습니다. WWW 양식에서 게시 된 데이터가 인코딩되는 방식과 동일한 방식으로 인코딩됩니다. 이는 application / x-www-form-urlencoded 미디어 유형과 동일한 방식입니다. 이것은 역사적 이유로 공백이 더하기 (+) 기호로 인코딩된다는 점에서»RFC 1738 인코딩 (rawurlencode () 참조)과 다릅니다.
영숫자가 아닌 모든 문자가 -_을 제외한 문자열을 반환합니다. 퍼센트 (%) 기호와 두 개의 16 진수로 교체되었습니다. 이것은 리터럴 문자가 특수 URL 구분 기호로 해석되지 않도록 보호하고 문자 변환 (일부 이메일 시스템과 같은)을 사용하여 전송 매체에 의해 URL이 엉망이되는 것을 방지하기 위해 RFC 1738에 설명 된 인코딩입니다.
두 개는 매우 유사하지만 후자 (rawurlencode)는 공백을 '%'와 두 개의 16 진수로 바꾸어 암호를 인코딩하는 데 적합합니다. 예를 들어 '+'가 다음과 같지 않은 경우 :
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">
유일한 차이점은 공백이 처리되는 방식에 있습니다.
urlencode-레거시 구현을 기반으로 공백을 +로 변환
rawurlencode- RFC 1738 기반으로 공간을 % 20으로 변환
차이점이있는 이유는 URL에서 +가 예약되어 있고 유효 (인코딩되지 않은)이기 때문입니다.
나는 다른 하나를 선택 해야하는 몇 가지 이유를 정말로보고 싶습니다 ... 나는 단지 하나를 골라서 최소한의 소란없이 영원히 사용할 수 있기를 원합니다.
공정하게도, 나는 이러한 결정을 내릴 때 따라야 할 간단한 전략을 가지고 있습니다.
" 허용 애플리케이션 " 을 요구 하는 HTTP / 1.1 사양 RFC 2616 인 것 같습니다.
클라이언트는 요청 라인을 구문 분석 할 때 Status-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는이 두 가지 형식 중 하나를 거부하는 사람을 본 적이 없어도이 사실을 염두에두고있는 것처럼 보이지만 사실상의 전략으로 채택하는 더 나은 전략을 생각할 수 없습니까?
조이!
%20
vs로 인코딩 된 공백+
rawurlencode()
대부분의 경우 에 사용 하는 가장 큰 이유 urlencode
는 텍스트 공간을 +
(더하기 기호)로 rawurlencode
인코딩하여 일반적으로 사용 되는 텍스트 공간을 인코딩 하기 때문입니다 %20
.
echo urlencode("red shirt");
// red+shirt
echo rawurlencode("red shirt");
// red%20shirt
인코딩 된 텍스트 쿼리를 허용하는 특정 API 끝 점이 %20
공백 을 볼 것으로 예상 하고 더하기 기호를 대신 사용하면 실패합니다. 분명히 이것은 API 구현마다 다르며 마일리지는 다를 수 있습니다.
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을 비교할 때 하나를 선택하십시오.