Home / Indice sezione
 www.icosaedro.it 

 PHP Nomi dei file e Unicode

Ultimo aggiornamento: 2012-03-19

Nei moderni file system i nomi dei file sono rappresentati dai codici Unicode. In Unix e Linux si usa di solito la codifica UTF-8 dell'Unicode, mentre in Windows si usa la codifica UTF-16. Sfortunatamente PHP non supporta le stringhe Unicode, per cui sorgono dei problemi quando si deve accedere a file o directory che contengono caratteri non-ASCII. Ad esempio, questi due file

Caffé Brillì.txt
日本語.txt

non sono in generale accessibili da PHP perché il primo riporta lettere accentate dell'alfabeto europeo occidentale, mentre il secondo contiene simboli ideografici giapponesi. Questo articolo vuole chiarire la situazione e propone una soluzione.

Indice

In breve

Il PHP accetta sorgenti scritti con un charset e un encoding arbitrari, purché i byte di valore da 0 a 127 rappresentino codici ASCII. Infatti tutte le parole chiave del linguaggio devono essere codificate in ASCII. Quindi vanno bene tutti i charset e le codifiche che hanno l'ASCII come subset: ISO-8859-* e UTF-8 vanno bene, mentre UTF-16 non funziona.

Le stringhe del PHP sono semplici sequenze di byte arbitrari, mentre non è specificato come questi codici si correlano ai caratteri di un particolare alfabeto. Per esempio:

$f1 = "Caffé Brillì.txt";
$f2 = "日本語.txt";

sono due stringhe, ma il contenuto esatto di queste stringhe dipende dal charset e dall'encoding del file di testo dove appaiono.

Nei sorgenti PHP le parole chiave del linguaggio sono codificate in ASCII (bytes da 0 a 127) mentre gli identificatori di costante, variabile, funzione e classe possono usare tutto lo psettro delle lettere, cifre e sottolineatura dell'ASCII più i byte da 127 a 255. Il PHP non ha idea di che cosa significano i byte da 127 a 255, ma si limita solo a confrontare i nomi a livello di byte per stabilire se due identificatori sono uguali o sono diversi. I nomi di funzione e di classe, e alcuni nomi di costante sono insensibili alla differenza tra lettere maiuscole e lettere minuscole del charset ASCII, ma questo non vale per i codici non-ASCII da 128 a 255, per cui ad esempio

function A(){}
function a(){}

dà errore perché la stessa funzione viene definita due volte, mentre

function À(){}
function à(){}

è valido perché si tratta di nomi diversi.

Lo scambio di nomi di file tra PHP e file system sottostante avviene attraverso stringhe. Per esempio, per creare un file useremo:

$f = fopen("Caffé Brillì.txt", "wb");

Come abbiamo detto, il nome del file è una sequenza di byte che dipende dal charset e dall'encoding del file di testo dove appaiono queste scritte. Ad esempio, se il file di testo è UTF-8, cioè il charset è Unicode e l'encoding è UTF-8, allora il codice di prima equivale al seguente:

$f = fopen("Caff\xC3\xA9 Brill\xC3\xAC.txt", "wb");

mentre se il file sorgente che abbiamo scritto è stato salvato come ISO-8859-1, allora il codice di prima equivale al seguente:

$f = fopen("Caff\xE9 Brill\xED.txt", "wb");

L'esatta codifica dipende da come abbiamo salvato il file del sorgente PHP. Ad esempio, in Notepad++ (vedi figura qui sotto) c'è il menu Format dove si sceglie l'encoding:

Cosa sia l'encoding ANSI lo sa solo l'autore del mitico Notepad++, ma probabilmente si tratta del solito ISO-8859-1. L'UCS-2 non è compatibile con PHP perché il linguaggio non riuscirebbe a riconoscere neanche le keyword. "Encode in UTF-8" non va bene perché è sottinteso "...con BOM", cioè all'inizio del file vengono messi i byte "\xEF\xBB\xBF" che disturbano la visualizzazione delle pagine WEB. Non rimane che una scelta soltanto: Encode in UTF-8 without BOM che è sano impostare come default del programma.

Premesso tutto questo, quale file scrive esattamente l'istruzione precedente? Dipende dal sistema operativo e dalla sua configurazione:

Conclusione. Se ci limitiamo ai nomi di file e ai path che contengono solo codici ASCII, allora non avremo problemi perché tutti i charset e tutti gli encoding di uso corrent hanno l'ASCII come sutto-insieme comune. Se, invece, vogliamo usare "caratteri estesi", allora dovremo procedere con grande cautela come spiegheremo nel seguito. Diciamo subito che dovremo stare attenti a codificare i sorgenti opportunamente, e poi dovremo sempre controllare la configurazione locale del sistema operativo per codificare correttamente i nomi dei file da leggere o da scrivere. Lo schema di lavoro è quindi questo:

Queste operazioni di conversione possono fallire per vari motivi, per cui dovremo tenere conto dei possibili errori.

Il locale corrente

In un mondo perfetto, i programmi dovrebbero specificare i nomi dei file come caratteri Unicode, e questo dovrebbe chiudere il discorso. Purtroppo il mondo non è perfetto: Unix e Linux non usano Unicode per default, mentre Windows usa Unicode ma PHP non è in grado di sfruttarlo e gira come programma "non-Unicode aware"". E'per questo ed altri motivi che esite l'intricato sistema delle preferenze di locale.

La funzione setlocale() permette di leggere la configurazione locale per la codifica dei nomi dei file e dei testi in generale:

$ctype = setlocale(LC_CTYPE, 0);

Questa istruzione non imposta nulla, ma ritorna il valore della variabile LC_CTYPE. Su Unix e Linux potremmo ottenere

en_US.UTF-8

dove UTF-8 è l'encoding dei nomi dei file, mentre su Windows potremmo ottenere qualcosa come

english_United States.1252

dove 1252 è la tabella di code page che traduce da byte a Unicode. La forma generale delle variabili LC_* è:

language[_territory][.codeset][@modifiers]

dove:

language è il l'ISO639 language code;
territory è l'ISO3166 country code;
codeset è l'encoding ID, come "ISO-8859-1" oppure il numero di code page sotto Windows, che è esattamente quello che interessa a noi;
modifiers sono i modificatori di formato per date e numeri che non ci interessano.

Configurare Windows Vista

Da Control Panel, Regional and Language Options possiamo impostare la lingua preferita, per esempio il giapponese, giusto per fare un esempio esotico interessante:

Imposta le preferenze di formattazione dei dati. I programmi usano questa impostazione per formattare importi monetari, numeri, date e altro ancora. Questo imposta anche il parametro LC_CTYPE al valore "Japanese_Japan.932 dove 932 è la tabella di code page giapponese. Sui computer occidentali tipicamente qui avremo invece qualcosa come "english_United States.1252".

Con questa impostazione il sistema operativo converte automaticamente da 932 a Unicode e viceversa i nomi dei file per i programmi non-Unicode compatibili, come PHP. E' ovvio che questa impostazione deve corrispondere a quella precedente. Questa impostazione NON imposta la variabile LC_CTYPE, ma solo la conversione automatica che fa il sistema operativo. Dopo aver cambiato questa impostazione è richiesto di riavviare la macchina.

Configurare Linux

Convertire i nomi file da PHP a file system

Convertire i nomi file da file system a PHP

Argomenti correlati


Umberto Salsi
Commenti
Contatto
Mappa
Home / Indice sezione
Still no comments to this page. Use the Comments link above to add your contribute.