Visual Basic 6 (VB6) al giorno d'oggi è diventato quasi una creatura mitologica: non importa quanto tu possa cercare di eliminarlo dal proprio arsenale di strumenti di sviluppo, prima o poi torna sempre a perseguitarti, nella maggior parte dei casi sotto le sembianze di un vecchio software gestionale e/o di utilità varia che svolge un numero di funzioni magari estremamente limitato, ma comunque rilevante nell'economia aziendale. Quando questo software smette di funzionare, si rende ahimé necessario riesumare l'ambiente di sviluppo e correggere il problema.
Oggi in ufficio ci è toccato assistere a questa ennesima resurrezione, che ha riguardato un vecchio client software che ancora viene utilizzato - tra le altre cose - per svolgere alcune saltuarie request HTTP a servizi esterni parimenti obsoleti. Nello specifico, il problema era legato a una vecchia funzione URLEncode nascosta da qualche parte del codice sorgente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
Function URLEncode(EncodeStr As String) As String Dim i As Integer Dim erg As String erg = EncodeStr ' *** First replace '%' chr erg = Replace(erg, "%", Chr(1)) ' *** then '+' chr erg = Replace(erg, "+", Chr(2)) For i = 0 To 255 Select Case i ' *** Allowed 'regular' characters Case 37, 43, 48 To 57, 65 To 90, 97 To 122 Case 1 ' *** Replace original % erg = Replace(erg, Chr(i), "%25") Case 2 ' *** Replace original + erg = Replace(erg, Chr(i), "%2B") Case 32 erg = Replace(erg, Chr(i), "+") Case 3 To 15 erg = Replace(erg, Chr(i), "%0" & Hex(i)) Case Else erg = Replace(erg, Chr(i), "%" & Hex(i)) End Select Next URLEncode = erg End Function |
Questa funzione, che funziona bene lavorando con stringhe in formato Windows-1252, presenta non pochi problemi quando occorre produrre un risultato in formato UTF8. Ad esempio, il carattere À verrà convertito in %C0, che non sarà considerato valido a seguito di un URLDecode su un sistema UTF8.
Per correggere il problema abbiamo rapidamente messo in piedi il seguente workaround: si tratta in buona sostanza di un convertitore di formato da UTF16 a UTF8 che precede l'URLEncode vero e proprio, rendendolo compatibile con la maggior parte delle funzionalità URLDecode native dei principali framework in uso di recente (PHP, ASP.NET, JAVA e così via).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
Private Declare Sub CopyToMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) Public Function URLEncode_UTF8( _ ByVal Text As String _ ) As String Dim Index1 As Long Dim Index2 As Long Dim Result As String Dim Chars() As Byte Dim Char As String Dim Byte1 As Byte Dim Byte2 As Byte Dim UTF16 As Long For Index1 = 1 To Len(Text) CopyToMemory Byte1, ByVal StrPtr(Text) + ((Index1 - 1) * 2), 1 CopyToMemory Byte2, ByVal StrPtr(Text) + ((Index1 - 1) * 2) + 1, 1 UTF16 = Byte2 UTF16 = UTF16 * 256 + Byte1 Chars = GetUTF8FromUTF16(UTF16) For Index2 = LBound(Chars) To UBound(Chars) Char = Chr(Chars(Index2)) If Char Like "[0-9A-Za-z]" Then Result = Result & Char Else Result = Result & "%" & Hex(Asc(Char)) End If Next Next URLEncode_UTF8 = Result End Function Private Function GetUTF8FromUTF16( _ ByVal UTF16 As Long _ ) As Byte() Dim Result() As Byte If UTF16 < &H80 Then ReDim Result(0 To 0) Result(0) = UTF16 ElseIf UTF16 < &H800 Then ReDim Result(0 To 1) Result(1) = &H80 + (UTF16 And &H3F) UTF16 = UTF16 \ &H40 Result(0) = &HC0 + (UTF16 And &H1F) Else ReDim Result(0 To 2) Result(2) = &H80 + (UTF16 And &H3F) UTF16 = UTF16 \ &H40 Result(1) = &H80 + (UTF16 And &H3F) UTF16 = UTF16 \ &H40 Result(0) = &HE0 + (UTF16 And &HF) End If GetUTF8FromUTF16 = Result End Function |
Una volta implementate le due funzioni, sarà sufficiente chiamare la prima, ovvero URLEncode_UTF8 (che include internamente la chiamata alla seconda) per ottenere una stringa URLEncoded in formato compatibile UTF-8.
Conclusione
Se vi siete imbattuti in questo articolo, è probabile che abbiate anche voi a che fare un problema del genere: ci auguriamo che questo contributo possa aiutarvi a risolverlo rapidamente.
Alla prossima!