İspat PHP'nin kaynak kodundadır.
Gelecekte istediğiniz zaman bu tür şeyleri kendi kendinize nasıl bulacağınız konusunda hızlı bir süreçten geçeceğim. Benimle birlikte, gözden geçirebileceğiniz bir sürü C kaynak kodu olacak (açıklarım). Bazı C fırçalamak istiyorsanız, başlamak için iyi bir yer bizim SO wiki .
Kaynak indirin (veya çevrimiçi göz atmak için http://lxr.php.net/ kullanın), işlev adı için tüm dosyaları grep, böyle bir şey bulacaksınız:
PHP 5.3.6 (en son yazma sırasında) url.c dosyasındaki yerel C kodundaki iki işlevi açıklar .
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);
}
Tamam, burada farklı olan ne?
Her ikisi de esasen sırasıyla iki farklı dahili işlevi çağırır : php_raw_url_encode ve php_url_encode
O halde git bu fonksiyonları ara!
Hadi php_raw_url_encode'a bakalım
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);
}
Ve tabii ki, 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;
}
İlerlemeden önce kısa bir bilgi birikimi olan EBCDIC, ASCII'ye benzeyen başka bir karakter seti , ancak toplam bir rakip. PHP her ikisiyle de uğraşmaya çalışır. Ama temel olarak, bu byte EBCDIC 0x4c byte L
ASCII'de değil, aslında bir <
. Burada karışıklığı gördüğünüze eminim.
Web sunucusu tanımladıysa, bu işlevlerin her ikisi de EBCDIC'yi yönetir.
Ayrıca, her ikisi de hexchars
bazı değerleri almak için karakter dizisi (think string type) araması kullanır , dizi şöyle açıklanır:
/* 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";
Bunun ötesinde, fonksiyonlar gerçekten farklı ve ASCII ve EBCDIC'de bunları açıklayacağım.
ASCII'deki farklılıklar:
UrlEncode:
- Giriş dizesinin başlangıç / bitiş uzunluğunu hesaplar, bellek ayırır
- Bir while döngüsü boyunca yürür, dizenin sonuna ulaşana kadar artar
- Şimdiki karakteri yakalar
- Karakter ASCII Char 0x20 (yani, bir "boşluk") değerine eşitse
+
, çıkış dizesine bir işaret ekleyin .
- Bir boşluk değilse ve aynı zamanda alfasayısal (
isalnum(c)
) değilse ve ayrıca ve , veya karakter değilse _
, 0 dizisi konumuna bir işaret çıkarırsak , dizi için arama yapmak için diziye bir dizi ararız ( (mevcut karakter) anahtarı için Apache'den char'ı onaltılık koda çeviren bir dizi ), daha sonra sağa doğru 4'e doğru kaydırırız, bu değeri 1 karakterine atarız ve 2 konumuna aynı formu atarız, ancak önceden oluşturmamız dışında mantıksal ve değerin 15 (0xF) olup olmadığını görmek ve bu durumda 1, aksi takdirde 0 değerini döndürmek. Sonunda, kodlanmış bir şey elde edersiniz.-
.
%
hexchars
os_toascii
c
- Sonunda bir boşluk değil, alfasayısal veya
_-.
karakterlerden biri, tam olarak ne olduğunu verir.
RAWURLENCODE:
- Dize için bellek ayırır
- İşlev çağrısında sağlanan uzunluğa göre yinelenir (URLENCODE ile olduğu gibi işlevde hesaplanmaz).
Not: Birçok programcı muhtemelen bir döngü yinelerler bu şekilde için, biraz hackish var görmemiştim değil standart kongre, ödeme dikkatine-döngüler için, bu atar En çok kullanılan x
ve y
üzerinde, çıkış kontrolleri len
0 ulaşan ve artışlarla hem x
ve y
. Biliyorum, beklediğiniz gibi değil, geçerli bir kod.
- Mevcut karakteri, içinde eşleşen bir karakter konumuna atar
str
.
- Mevcut karakterin alfasayısal mı yoksa karakterlerden biri olup olmadığını kontrol eder
_-.
ve değilse, aramaları önceden oluşturduğu URLENCODE ile hemen hemen aynı atamayı yaparız, ancak bunun y++
yerine farklı şekilde artarız to[1]
, çünkü dizeler farklı şekillerde inşa ediliyor, ancak yine de aynı hedefe ulaşıyor.
- Döngü bittiğinde ve uzunluk gittiğinde, aslında
\0
baytı atayarak dizeyi sonlandırır .
- Kodlanmış dizeyi döndürür.
farklılıklar:
- UrlEncode alanı kontrol eder, bir + işareti atar, RawURLEncode kaydetmez.
- UrlEncode
\0
dizeye bir bayt atamaz, RawUrlEncode yapar (bu bir tartışma noktası olabilir)
- Onlar bir hatalı biçimlendirilmiş dizeleri ile taşma eğilimli olabilir, differntly yineleme, ben değilim sadece düşündüren bu ve ben değil aslında araştırdık.
Temel olarak farklı şekilde tekrar ederler, ASCII 20'de bir + işareti atar.
EBCDIC'deki farklılıklar:
UrlEncode:
- ASCII ile aynı yineleme kurulumu
- Hala "boşluk" karakterini + işaretine çeviriyor . Not-- Bunun EBCDIC'de derlenmesi gerektiğini mi yoksa bir hata ile mi karşılaşacağınızı düşünüyorum? Birisi bunu düzenleyebilir ve onaylayabilir mi?
- Bu kontroller mevcut karakter önce karakter ise
0
bir olmanın dışında, .
ya -
, YA az A
ama daha büyük Char 9
, OR büyüktür Z
az ve a
ancak bir _
. VEYA daha büyük z
(evet, EBCDIC ile çalışmak biraz karışıktır). Bunlardan herhangi biriyle eşleşirse, ASCII sürümünde bulunanla benzer bir arama yapın (sadece os_toascii'de bir arama gerektirmez).
RAWURLENCODE:
- ASCII ile aynı yineleme kurulumu
- URL Kodlamasının EBCDIC sürümünde açıklananla aynı kontrol, ancak bundan büyükse URL kodundan
z
hariç tutulur ~
.
- ASCII RawUrlEncode ile aynı atama
- Hala
\0
dönmeden önce dizeye bayt ekleniyor .
Genel Özet
- Her ikisi de aynı hexchars arama tablosunu kullanır
- URIEncode \ 0 ile bir dizeyi sonlandırmaz, raw yapar.
- EBCDIC'de çalışıyorsanız,
~
UrlEncode'un çalışmadığını yönettiği için RawUrlEncode kullanmanızı öneririm ( bu bildirilen bir sorundur ). ASCII ve EBCDIC 0x20'nin her ikisinin de boşluk olduğunu belirtmek gerekir.
- Farklı bir şekilde tekrar ederler, biri daha hızlı olabilir, biri hafızaya veya dize tabanlı istismarlara eğilimli olabilir.
- URIEncode içine boşluk
+
bırakıyor, RawUrlEncode %20
dizi aramaları ile boşluk bırakıyor .
Feragatname: Yıllardır C'ye dokunmadım ve EBCDIC'e gerçekten uzun zamandır bakmadım. Eğer bir yerde yanılıyorsam bana haber ver.
Önerilen uygulamalar
Tüm bunlara dayanarak, rawurlencode çoğu zaman gitmenin yoludur. Jonathan Fingland'ın cevabında gördüğünüz gibi, çoğu durumda buna sadık kalın. URI bileşenleri için modern şema ile ilgilenir, burada urlencode şeyleri eski okul yolunda yapar, burada + "uzay" anlamına gelir.
Eski biçim ve yeni biçimler arasında dönüştürme yapmaya çalışıyorsanız, kodunuzun yukarı çıkmadığından emin olun ve yanlışlıkla çift kodlama veya bunun etrafındaki benzer "oops" senaryolarını kullanarak kodu çözülmüş + işareti olan bir alanı boşluğa dönüştürün. boşluk /% 20 / + sorunu.
Yeni formatı tercih etmeyen eski bir yazılımla eski bir sistem üzerinde çalışıyorsanız, urlencode ile sadık kalın, ancak% 20'nin aslında çalıştığı eski standart% 20 altında olduğu gibi geriye dönük olarak uyumlu olacağına inanıyorum. tercihli. Oyun oynamak için bir şans verin, sizin için nasıl çalıştığını bize bildirin.
Temel olarak, EBCDIC sisteminiz gerçekten senden nefret etmedikçe çiğ kalmalısınız. Çoğu programcı 2000 yılından sonra, hatta 1990'dan sonra yapılan herhangi bir sistemde asla EBCDIC ile karşılaşmayacaktır (bu zorlayıcıdır, ancak yine de bence muhtemelen).