सबूत PHP के स्रोत कोड में है।
मैं आपको भविष्य में किसी भी समय इस तरह की चीज़ का पता लगाने की एक त्वरित प्रक्रिया के माध्यम से ले जाऊंगा। मेरे साथ सहन करें, बहुत सारे सी सोर्स कोड होंगे जिन्हें आप स्किम कर सकते हैं (मैं इसे समझाता हूं)। यदि आप कुछ सी पर ब्रश करना चाहते हैं, तो शुरू करने के लिए एक अच्छी जगह हमारे एसओ विकी है ।
स्रोत डाउनलोड करें (या इसे ऑनलाइन ब्राउज़ करने के लिए 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
तो उन कार्यों के लिए देखो!
आओ हम 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;
}
इससे पहले कि मैं आगे बढ़ूँ , ईबीसीडीआईसी एक और चरित्र सेट है , जो एएससीआईआई के समान है, लेकिन कुल प्रतियोगी है। 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 में समझाने जा रहा हूं।
ASCII में अंतर:
URLENCODE:
- इनपुट स्ट्रिंग की एक शुरुआत / अंत लंबाई की गणना करता है, मेमोरी आवंटित करता है
- थोड़ी देर लूप के माध्यम से चलता है, जब तक हम स्ट्रिंग के अंत तक नहीं पहुंचते तब तक वेतन वृद्धि
- वर्तमान चरित्र को पकड़ लेता है
- यदि वर्ण ASCII चार 0x20 (यानी, एक "स्थान") के बराबर है,
+
तो आउटपुट स्ट्रिंग में एक संकेत जोड़ें ।
- यदि यह स्थान नहीं है, और यह अल्फ़ान्यूमेरिक (
isalnum(c)
) भी नहीं है , और यह भी नहीं है और _
, -
या .
चरित्र, तो हम, %
सरणी स्थिति 0 के लिए एक संकेत आउटपुट करते हैं, hexchars
सरणी के लिए लुकअप के लिए os_toascii
सरणी के लिए एक सरणी देखें ( (वर्तमान चरित्र) की कुंजी के लिए अपाचे से एक सरणी जो हेक्स कोड में अनुवाद करता हैc
), हम तब बिटवाइस 4 से दाएं शिफ्ट करते हैं, उस मान को चरित्र 1 में असाइन करते हैं, और स्थिति 2 में हम उसी लुकअप को असाइन करते हैं, सिवाय इसके कि हम पूर्ववत करें एक तार्किक और यह देखने के लिए कि मान 15 (0xF) है, और उस स्थिति में 1 लौटाएं, या 0 अन्यथा। अंत में, आप कुछ एन्कोडेड के साथ समाप्त करेंगे।
- यदि यह समाप्त होता है तो यह एक स्थान नहीं है, यह अल्फ़ान्यूमेरिक या
_-.
वर्णों में से एक है , यह बिल्कुल वही है जो यह है।
RAWURLENCODE:
- स्ट्रिंग के लिए मेमोरी आवंटित करता है
- फ़ंक्शन कॉल में प्रदान की गई लंबाई के आधार पर Iterates (URLENCODE के साथ फ़ंक्शन में गणना नहीं की गई है)।
नोट: कई प्रोग्रामर ने शायद लूप के लिए इस तरह से कभी नहीं देखा है, यह कुछ हद तक हैक है और सबसे अधिक-लूप के साथ उपयोग किए जाने वाले मानक सम्मेलन पर ध्यान नहीं देते हैं, यह असाइन करता है x
और y
, len
0 तक पहुंचने के लिए बाहर निकलने के लिए चेक करता है , और दोनों को बढ़ाता है x
और y
। मुझे पता है, यह वह नहीं है जिसकी आप अपेक्षा करेंगे, लेकिन यह मान्य कोड है।
- वर्तमान चरित्र को एक मिलान वर्ण स्थिति में असाइन करता है
str
।
- यह जाँचता है कि क्या वर्तमान वर्ण अल्फ़ान्यूमेरिक है, या वर्णों में से एक है
_-.
, और यदि ऐसा नहीं है, तो हम URLENCODE के साथ लगभग वही असाइनमेंट करते हैं जहाँ यह लुकअप्स को बेहतर बनाता है, हालाँकि, हम अलग-अलग वृद्धि करते हैं, इसका उपयोग करते y++
हुए to[1]
, क्योंकि यह है स्ट्रिंग्स को अलग-अलग तरीकों से बनाया जा रहा है, लेकिन अंत में एक ही लक्ष्य तक पहुँच सकते हैं।
- जब लूप किया जाता है और लंबाई चली जाती है, यह वास्तव में स्ट्रिंग को समाप्त करता है,
\0
बाइट को निर्दिष्ट करता है ।
- यह एन्कोडेड स्ट्रिंग लौटाता है।
अंतर:
- अंतरिक्ष के लिए UrlEncode चेक, एक + संकेत प्रदान करता है, RawURLEncode नहीं करता है।
- UrlEncode
\0
स्ट्रिंग को बाइट असाइन नहीं करता है , RawUrlEncode करता है (यह एक म्यूट बिंदु हो सकता है)
- वे अलग तरीके से पुनरावृत्ति करते हैं, एक विकृत विकृतियों के साथ बह निकला हो सकता है, मैं केवल यह सुझाव दे रहा हूं और मैंने इसकी जांच नहीं की है।
वे मूल रूप से अलग तरह से पुनरावृति करते हैं, एक ASCII 20 की स्थिति में एक + संकेत प्रदान करता है।
EBCDIC में अंतर:
URLENCODE:
- ASCII के साथ समान पुनरावृत्ति सेटअप
- फिर भी "स्पेस" कैरेक्टर को + साइन करने के लिए। नोट-- मुझे लगता है कि इसे EBCDIC में संकलित करने की आवश्यकता है या आप बग के साथ समाप्त होंगे? क्या कोई इसे संपादित और पुष्टि कर सकता है?
- यह जाँच करता है कि क्या वर्तमान चार पहले एक चार है
0
, .
या होने के अपवाद के साथ -
, या उससे कम है, A
लेकिन चार से अधिक है 9
, या इससे अधिक है Z
और इससे कम है, a
लेकिन नहीं _
। या इससे अधिक z
(हाँ, EBCDIC काम करने के लिए गड़बड़ है)। यदि यह उनमें से किसी से मेल खाता है, तो ASCII संस्करण में पाया गया एक समान लुकअप करें (यह केवल os_toascii में लुकअप की आवश्यकता नहीं है)।
RAWURLENCODE:
- ASCII के साथ समान पुनरावृत्ति सेटअप
- URL एनकोड के EBCDIC संस्करण में वर्णित समान जांच, इस अपवाद के साथ कि यदि यह इससे अधिक है
z
, तो यह ~
URL एनकोड से बाहर है।
- ASCII RawUrlEncode के रूप में समान कार्यभार
- फिर भी
\0
वापसी से पहले स्ट्रिंग को बाइट को जोड़ना ।
ग्रैंड सारांश
- दोनों एक ही हेक्सचार लुकअप टेबल का उपयोग करते हैं
- URIEncode \ 0, कच्चे करता है के साथ एक स्ट्रिंग समाप्त नहीं करता है।
- यदि आप EBCDIC में काम कर रहे हैं, तो मैं RawUrlEncode का उपयोग करने का सुझाव दूंगा, क्योंकि यह प्रबंधित करता है
~
कि UrlEncode नहीं करता है ( यह एक रिपोर्ट की गई समस्या है )। यह ध्यान देने योग्य है कि ASCII और EBCDIC 0x20 दोनों स्थान हैं।
- वे अलग तरह से पुनरावृत्ति करते हैं, एक तेज हो सकता है, कोई स्मृति या स्ट्रिंग आधारित कारनामों से ग्रस्त हो सकता है।
- URIEncode में एक जगह बनाता है
+
, RawUrlEncode %20
सरणी लुकअप के माध्यम से एक जगह बनाता है ।
अस्वीकरण: मैंने वर्षों में सी को नहीं छुआ है, और मैंने वास्तव में लंबे समय में EBCDIC को नहीं देखा है। अगर मैं कहीं गलत हूं, तो मुझे बताएं।
सुझाए गए कार्यान्वयन
इन सबके आधार पर, रॉर्लेंकोड सबसे अधिक बार जाने का मार्ग है। जैसा कि आप जोनाथन फिंगलैंड के उत्तर में देखते हैं, ज्यादातर मामलों में इसके साथ रहना चाहिए। यह URI घटकों के लिए आधुनिक योजना से संबंधित है, जहां urlencode पुराने स्कूल के रास्ते को करता है, जहां + का अर्थ है "स्थान।"
यदि आप पुराने प्रारूप और नए प्रारूपों के बीच रूपांतरण करने की कोशिश कर रहे हैं, तो सुनिश्चित करें कि आपका कोड ऊपर नहीं जाता है और कुछ ऐसा है जो एक डिकोड किया गया है + गलती से डबल-एन्कोडिंग द्वारा अंतरिक्ष में प्रवेश करता है, या इसके चारों ओर समान "उफ़" परिदृश्य। अंतरिक्ष / 20% / + मुद्दा।
यदि आप पुराने सॉफ़्टवेयर के साथ एक पुराने सिस्टम पर काम कर रहे हैं जो नए प्रारूप को पसंद नहीं करता है, तो urlencode के साथ रहें, हालांकि, मेरा मानना है कि% 20 वास्तव में पीछे की ओर संगत होगा, जैसा कि पुराने मानक% 20 के तहत काम किया गया था, बस नहीं किया गया था पसंदीदा। यदि आप खेलने के लिए तैयार हैं, तो इसे शॉट दें, हमें बताएं कि यह आपके लिए कैसे काम करता है।
मूल रूप से, आपको कच्चे के साथ रहना चाहिए, जब तक कि आपका ईबीसीडीआईसी सिस्टम आपको वास्तव में घृणा न करे। वर्ष 2000 के बाद बने किसी भी सिस्टम पर अधिकांश प्रोग्रामर कभी भी EBCDIC में नहीं चलेंगे, शायद 1990 भी (जो कि धक्का दे रहा है, लेकिन अभी भी मेरी राय में संभव है)।