Un processus typique est: L'URL du navigateur ou du client code les paramètres et les envoie (par exemple,? Nom =% E4% F0% E0% E2% E5% F2 ), et le serveur reçoit une séquence d'octet échappée par le signe en pourcentage. Pour restaurer le texte UTF-8 correct, deux étapes sont généralement requises:
Décodez le codage de l'URL ( RawurLDECODE / URLDECODE ) pour obtenir la séquence d'octet d'origine. php.net +1
Convertissez cette séquence d'octets à partir du codage unique à un octet (par exemple Windows-1251, KOI8-R, CP866, etc.) en UTF-8. Pour les encodages cyrilliques communs, Convert_Cyr_String peut compléter les conversions du jeu de caractères lorsqu'elles sont prises en charge par la version PHP du serveur. php.net
Remarque: convert_cyr_string est déprécié depuis PHP 7.4 et supprimé dans PHP 8.0; Les bibliothèques MB_CONVERT_ENCODING / ICONV ou UTF-8 tierces doivent être utilisées en premier dans de nouveaux environnements. La compatibilité et les solutions alternatives sont données ci-dessous. php.net
convert_cyr_string (String $ str, string $ from, string $ to) utilise le code d'identification à un seul caractère, et l'identification commune est la suivante:
K - Koi8-R
W - Windows-1251
I - ISO-8859-5
A / D - X-CP866 (DOS CP866)
M - x-mac-cyrillique. php.net
Voici une fonction PHP pratique: recevez une chaîne qui peut être codée par URL et utilise une sorte de chaîne codée cyrillique (de la chaîne de requête ou du segment de chemin), décode et convertit en UTF-8. Remarque : Avant d'utiliser, veuillez vous assurer que votre version PHP prend toujours en charge Convert_Cyr_string (PHP ≤ 7.3). Si votre environnement de course est PHP 8+, veuillez passer à la section suivante pour voir l'alternative.
<span><span><span class="hljs-meta"><?php</span></span><span>
<span class="hljs-comment">/**
* Volonté URL paramètre(Peut-être encodé pour le cyrillique d'un octet et échappé par pourcentage de signe)Standardisé à UTF-8 Chaîne。
*
* $rawUrlPart: original URL partie(Par exemple $_GET['name'],Ou de PATH_INFO/Fragments obtenus dans l'itinéraire)
* $sourceCode: Identification du code source,utiliser convert_cyr_string Code de lettre unique('w','k','i','a','d','m')
*
* retour UTF-8 Chaîne(若无法转换则retouroriginal经过 rawurldecode 的Chaîne)
*/</span>
</span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">normalize_cyrillic_url_param</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-keyword">string</span></span></span><span> </span><span><span class="hljs-variable">$rawUrlPart</span></span><span>, </span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-variable">$sourceCode</span></span><span> = </span><span><span class="hljs-string">'w'</span></span><span>): </span><span><span class="hljs-title">string</span></span><span> {
</span><span><span class="hljs-comment">// 先把百分号转义还原pouroriginal字节</span></span><span>
</span><span><span class="hljs-variable">$decoded</span></span><span> = </span><span><span class="hljs-title function_ invoke__">rawurldecode</span></span><span>(</span><span><span class="hljs-variable">$rawUrlPart</span></span><span>); </span><span><span class="hljs-comment">// Octets réservés,Ne le faites pas + Se tourner vers l'espace(Applicable à path segment);Si de query Et il y a +,Disponible urldecode()</span></span><span>
</span><span><span class="hljs-comment">// Si le système a convert_cyr_string(Avis:exister PHP 8+ Supprimé)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'convert_cyr_string'</span></span><span>)) {
</span><span><span class="hljs-comment">// Encoder d'abord un seul octet(sourceCode)Se convertir windows-1251('w'),</span></span><span>
</span><span><span class="hljs-comment">// Alors windows-1251 Se tourner vers UTF-8(utiliser mb_convert_encoding)</span></span><span>
</span><span><span class="hljs-variable">$asWin1251</span></span><span> = </span><span><span class="hljs-title function_ invoke__">convert_cyr_string</span></span><span>(</span><span><span class="hljs-variable">$decoded</span></span><span>, </span><span><span class="hljs-variable">$sourceCode</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>);
</span><span><span class="hljs-comment">// Volonté windows-1251 二进制字节Se tourner vers UTF-8 Chaîne</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'mb_convert_encoding'</span></span><span>)) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">mb_convert_encoding</span></span><span>(</span><span><span class="hljs-variable">$asWin1251</span></span><span>, </span><span><span class="hljs-string">'UTF-8'</span></span><span>, </span><span><span class="hljs-string">'Windows-1251'</span></span><span>);
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-comment">// En tant que sauvegarde,essayer iconv(comme果Disponible)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'iconv'</span></span><span>)) {
</span><span><span class="hljs-variable">$utf8</span></span><span> = @</span><span><span class="hljs-title function_ invoke__">iconv</span></span><span>(</span><span><span class="hljs-string">'CP1251'</span></span><span>, </span><span><span class="hljs-string">'UTF-8//IGNORE'</span></span><span>, </span><span><span class="hljs-variable">$asWin1251</span></span><span>);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$utf8</span></span><span> !== </span><span><span class="hljs-literal">false</span></span><span> ? </span><span><span class="hljs-variable">$utf8</span></span><span> : </span><span><span class="hljs-variable">$asWin1251</span></span><span>;
}
</span><span><span class="hljs-comment">// 都不Disponible时,retouroriginal解码Chaîne</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$asWin1251</span></span><span>;
}
}
</span><span><span class="hljs-comment">// Sinon convert_cyr_string(comme PHP 8+),直接retouroriginal解码Chaîne,让调用方utiliser替代方案</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$decoded</span></span><span>;
}
</span></span>Exemple d'utilisation:
<span><span><span class="hljs-comment">// Hypothèses URL pour: /?name=%D0%9C%D0%B8%D1%80</span></span><span>
</span><span><span class="hljs-variable">$raw</span></span><span> = </span><span><span class="hljs-variable">$_GET</span></span><span>[</span><span><span class="hljs-string">'name'</span></span><span>] ?? </span><span><span class="hljs-string">''</span></span><span>;
</span><span><span class="hljs-variable">$name</span></span><span> = </span><span><span class="hljs-title function_ invoke__">normalize_cyrillic_url_param</span></span><span>(</span><span><span class="hljs-variable">$raw</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>); </span><span><span class="hljs-comment">// Hypothèses客户端以 Windows-1251 envoyer</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$name</span></span><span>; </span><span><span class="hljs-comment">// La sortie est correcte UTF-8 nom</span></span><span>
</span></span>Le décodage des échappés % doit être sélectionné en fonction de votre source de paramètre RawurLDECOD () (plus adapté aux segments de chemin) ou UrLDECODE () (lorsque + représente l'espace dans la chaîne de requête). Pour les différences et l'utilisation recommandée des deux, veuillez vous référer à la documentation officielle. php.net guides.codepath.com
Pour les nouveaux projets ou les environnements PHP 8+, il est recommandé d'utiliser MB_DETECT_ENCODING + MB_CONVERT_ENCODING / ICONV , ou pour permettre aux clients d'utiliser UTF-8 uniformément (meilleures pratiques). Exemple:
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">normalize_cyrillic_url_param_modern</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-keyword">string</span></span></span><span> </span><span><span class="hljs-variable">$rawUrlPart</span></span><span>, </span><span><span class="hljs-keyword">array</span></span><span> </span><span><span class="hljs-variable">$tryEncodings</span></span><span> = [</span><span><span class="hljs-string">'Windows-1251'</span></span><span>,</span><span><span class="hljs-string">'KOI8-R'</span></span><span>,</span><span><span class="hljs-string">'CP866'</span></span><span>]) : </span><span><span class="hljs-title">string</span></span><span> {
</span><span><span class="hljs-variable">$decoded</span></span><span> = </span><span><span class="hljs-title function_ invoke__">rawurldecode</span></span><span>(</span><span><span class="hljs-variable">$rawUrlPart</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'mb_detect_encoding'</span></span><span>) && </span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'mb_convert_encoding'</span></span><span>)) {
</span><span><span class="hljs-comment">// essayer检测并转换到 UTF-8</span></span><span>
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$tryEncodings</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$enc</span></span><span>) {
</span><span><span class="hljs-comment">// 检测字节串是否pour此编码(Les tests peuvent ne pas être fiables,故采用essayer转换后判断)</span></span><span>
</span><span><span class="hljs-variable">$maybe</span></span><span> = @</span><span><span class="hljs-title function_ invoke__">mb_convert_encoding</span></span><span>(</span><span><span class="hljs-variable">$decoded</span></span><span>, </span><span><span class="hljs-string">'UTF-8'</span></span><span>, </span><span><span class="hljs-variable">$enc</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$maybe</span></span><span> !== </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-comment">// Vérification simple:Est-ce similaire à la longueur d'octet d'origine après la conversion?(Non 100% fiable,Mais pratique)</span></span><span>
</span><span><span class="hljs-variable">$back</span></span><span> = @</span><span><span class="hljs-title function_ invoke__">mb_convert_encoding</span></span><span>(</span><span><span class="hljs-variable">$maybe</span></span><span>, </span><span><span class="hljs-variable">$enc</span></span><span>, </span><span><span class="hljs-string">'UTF-8'</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$back</span></span><span> !== </span><span><span class="hljs-literal">false</span></span><span> && </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$back</span></span><span>) >= </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$decoded</span></span><span>) - </span><span><span class="hljs-number">2</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$maybe</span></span><span>;
}
}
}
}
</span><span><span class="hljs-comment">// 最后退回original解码后的Chaîne(Probablement déjà UTF-8)</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$decoded</span></span><span>;
}
</span></span>De plus, les bibliothèques tierces matures (telles que Voku / Portable-UTF8 , etc.) peuvent également être utilisées pour faire face aux problèmes de codage / normalisation complexes, en particulier dans les systèmes de production qui nécessitent une robustesse élevée. Github
Priorité : La meilleure solution consiste à permettre à tous les clients d'utiliser UTF-8 uniformément (expliqué dans HTML <Meta Charset = "UTF-8"> , en-tête HTTP, documentation API). C'est la meilleure pratique pour éviter fondamentalement le code brouillé.
Sélection de la fonction de décodage : Lors de la réception du codage de l'URL, s'il s'agit de la partie de la requête ( ? A = B + C ), URLDECODE () transformera + en un espace; S'il s'agit d'un segment de chemin de chemin, RawurLDECODE () est préféré. php.net +1
Conversion côté serveur : lorsque seules des données historiques ou des systèmes tiers peuvent être traitées, la séquence d'octet est convertie en UTF-8 en utilisant la chaîne de conversion illustrée ci-dessus ( RawurldOcode → Convert_Cyr_String (si disponible) ou MB_CONVERT_ENCODING / ICONV ). php.net +1
Détection et repli : Le codage de détection automatique n'est pas précis à 100%. Il est recommandé d'ajouter des jugements de «crédibilité» aux scénarios clés (tels que la vérification de la cohérence après détection puis de la conversion inversée) et d'enregistrer des échecs pour une intervention manuelle ou l'ajout de règles spécifiques.
Remarque de dépréciation : convert_cyr_string est marqué comme déprécié dans PHP 7.4 et supprimé dans PHP 8.0; Si votre code doit s'exécuter dans un environnement PHP moderne pendant longtemps, veuillez implémenter une alternative compatible ( MB_CONVERT_ENCODING / ICONV / bibliothèque tierce). php.net
Scénario A: Le client hérité envoie des paramètres (requête) avec KOI8-R, et le serveur espère obtenir UTF-8:
<span><span><span class="hljs-variable">$raw</span></span><span> = </span><span><span class="hljs-variable">$_GET</span></span><span>[</span><span><span class="hljs-string">'q'</span></span><span>]; </span><span><span class="hljs-comment">// original %xx Chaîne</span></span><span>
</span><span><span class="hljs-variable">$bytes</span></span><span> = </span><span><span class="hljs-title function_ invoke__">rawurldecode</span></span><span>(</span><span><span class="hljs-variable">$raw</span></span><span>); </span><span><span class="hljs-comment">// Obtenez des octets binaires</span></span><span>
</span><span><span class="hljs-comment">// 若Disponible convert_cyr_string:</span></span><span>
</span><span><span class="hljs-variable">$win</span></span><span> = </span><span><span class="hljs-title function_ invoke__">convert_cyr_string</span></span><span>(</span><span><span class="hljs-variable">$bytes</span></span><span>, </span><span><span class="hljs-string">'k'</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>); </span><span><span class="hljs-comment">// koi8-r -> windows-1251</span></span><span>
</span><span><span class="hljs-variable">$utf8</span></span><span> = </span><span><span class="hljs-title function_ invoke__">mb_convert_encoding</span></span><span>(</span><span><span class="hljs-variable">$win</span></span><span>, </span><span><span class="hljs-string">'UTF-8'</span></span><span>, </span><span><span class="hljs-string">'Windows-1251'</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$utf8</span></span><span>;
</span></span>Scénario B: Environnement PHP 8+, essayez la conversion automatique à l'aide de méthodes modernes:
<span><span><span class="hljs-variable">$raw</span></span><span> = </span><span><span class="hljs-variable">$_GET</span></span><span>[</span><span><span class="hljs-string">'q'</span></span><span>];
</span><span><span class="hljs-variable">$bytes</span></span><span> = </span><span><span class="hljs-title function_ invoke__">rawurldecode</span></span><span>(</span><span><span class="hljs-variable">$raw</span></span><span>);
</span><span><span class="hljs-variable">$utf8</span></span><span> = </span><span><span class="hljs-title function_ invoke__">normalize_cyrillic_url_param_modern</span></span><span>(</span><span><span class="hljs-variable">$raw</span></span><span>, [</span><span><span class="hljs-string">'Windows-1251'</span></span><span>,</span><span><span class="hljs-string">'KOI8-R'</span></span><span>,</span><span><span class="hljs-string">'CP866'</span></span><span>]);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$utf8</span></span><span>;
</span></span>convert_cyr_string était autrefois une fonction pratique pour gérer l'échange entre les codages cyrilliques à un octet, et les codes pris en charge incluent K, W, I, A, D, m . Cependant, cette fonction est obsolète dans PHP 7.4 et supprimée dans PHP 8.0. Il est recommandé que les nouveaux projets utilisent à la place MB_Convert_encoding / iconv ou tiers. php.net
Face au problème des paramètres d'URL brouillés, la clé est: décoder d'abord correctement le signe pourcentage ( RawurldEcode / UrlDecode ), puis convertir la séquence d'octets en UTF-8 en fonction du codage de source réel. Lors du choix des fonctions de décodage pour le chemin et la requête, faites attention aux différences dans les espaces de manutention ( + ) entre les deux. php.net +1
La stratégie à long terme la plus sécurisée consiste à utiliser UTF-8 de manière unifiée et à convenir clairement sur les spécifications de codage dans les documents d'interface et les implémentations des clients; Lorsque des données historiques ou tierces sont nécessaires, la chaîne de conversion ci-dessus est adoptée et le mécanisme de détection et de secours est ajouté pour assurer la robustesse. GitHub Php.net
Étiquettes associées:
URL