2010-04-13 19 views
7

Gestisco un forum progettato per supportare un gruppo internazionale di matematica. Di recente l'ho convertito in unicode per un migliore supporto di personaggi internazionali. Nel debug di questa conversione, ho scoperto che non tutti i caratteri Unicode sono considerati come XHTML validi (il sito Web pertinente sembra essere http://www.w3.org/TR/unicode-xml/). Uno dei passaggi che il software del forum attraversa prima di presentare i post al browser è un passaggio di validazione/sanificazione XHTML. Sembra un'idea ragionevole che a quel punto dovrebbe rimuovere tutti i caratteri Unicode che XHTML non gradisce.Come rimuovere i caratteri Unicode che XHTML considera non validi utilizzando php?

Quindi la mia domanda è:

Esiste uno standard (o migliore) modo di fare questo in PHP?

(Il forum è scritto in PHP, tra l'altro.)

immagino che il fail-safe sarebbe un semplice str_replace (se questo è anche il migliore, ho bisogno di fare qualcosa in più per assicurarsi funziona correttamente con unicode?) ma ciò comporterebbe il dover esaminare attentamente la DTD XHTML (o la pagina W3 di riferimento) per capire quali caratteri elencare nella ricerca di str_replace, quindi se questa è la il modo migliore, qualcuno lo ha già fatto in modo da poter rubare, errare, copiare, vero?

(Per inciso, il personaggio che ha causato il problema era U + 000C, il 'formfeed', che (secondo la pagina W3) è valido HTML ma XHTML valido!)

risposta

2

Ho trovato una funzione che potrebbe fare quello che vuoi sul phpedit.net.

vi posterò la funzione per l'archivio, i crediti per LTP su PHPEdit.net:

/** 
* Removes invalid XML 
* 
* @access public 
* @param string $value 
* @return string 
*/ 
function stripInvalidXml($value) 
{ 
    $ret = ""; 
    $current; 
    if (empty($value)) 
    { 
     return $ret; 
    } 

    $length = strlen($value); 
    for ($i=0; $i < $length; $i++) 
    { 
     $current = ord($value{$i}); 
     if (($current == 0x9) || 
      ($current == 0xA) || 
      ($current == 0xD) || 
      (($current >= 0x20) && ($current <= 0xD7FF)) || 
      (($current >= 0xE000) && ($current <= 0xFFFD)) || 
      (($current >= 0x10000) && ($current <= 0x10FFFF))) 
     { 
      $ret .= chr($current); 
     } 
     else 
     { 
      $ret .= " "; 
     } 
    } 
    return $ret; 
} 
+0

Direi che è più veloce del metodo preg_replace (soprattutto dato il commento sulla velocità su http://php.net/manual/en/regexp.reference.unicode.php), ma soffre dello stesso inconveniente che devo capire la mia whitelist! (Vedi il commento sopra sull'essere pigri!) –

+0

Non è necessario calcolare la propria white-list. I caratteri sono consentiti in base al codice ASCII e vengono sostituiti con uno spazio quando non rientrano nell'intervallo specificato dalla funzione. Sono abbastanza sicuro che questo è tutto ciò di cui hai bisogno, la white-list è già nella funzione. – Bas

+0

Certo, c'è una * lista bianca nella funzione, ma come faccio a sapere che è la whitelist corretta? Ad esempio, 0xC è consentito in HTML ma non in XHTML. Se sto lavorando da una whitelist, dovrebbe essere generato in qualche modo dalla DTD. –

1

Supponendo che l'input è utf8, è può rimuovere le gamme Unicode con qualcosa di simile

preg_replace('~[\x{17A3}-\x{17D3}]~u', '', $input); 

Un altro, e meglio, l'approccio è quello di rimuovere tutto ciò che per impostazione predefinita e solo caratteri whitelist che si desidera vedere. Le proprietà Unicode (\ p) sono abbastanza pratiche per questo. Ad esempio, rimuove tutto tranne lettere e numeri (Unicode):

preg_replace('~[^\p{L}\p{N}]~u', '', $input) 
+0

Il mio problema con uno di questi approcci è che devo passare attraverso la DTD per estrarre la whitelist o blacklist contro cui confrontarsi. Speravo che qualcuno lo avesse già fatto per me! Non credo che ci sia un '\ p {XHTML}' per tutti quei caratteri che sono XHTML validi, vero? (Sono un matematico e siamo fondamentalmente un gruppo pigro - se qualcun altro ha già risolto il problema, allora non vogliamo disturbarci a farlo di nuovo!) –

+0

non sono a conoscenza neanche di una tale soluzione, ma se stai cercando un modo semplice e veloce, puoi semplicemente convertire tutto tranne lettere-numeri-punteggiatura in entità numeriche. – user187291

+0

La conversione di "tutto eccetto" in entità non funziona. Se invio un carattere al di fuori del set valido, anche se codificato come entità, il browser si lamenterà. (Dovrei forse chiarire che sto servendo XHTML + MathML in modo che * abbia * per essere valido al 100% - Non posso fare affidamento sul browser per ignorare un'entità non valida.) –

Problemi correlati