PHP ip2long() madness

Capita abbastanza spesso di dover salvare un indirizzo IP in una tabella di database. La teoria e la pratica insegnano quanto sia meglio salvare non la string CHAR(15) dell’IP, ma la sua rappresentazione numerica (si salva spazio, le ricerche sono più pratiche, gli indici velocissimi).

Si dà il caso, poi, che sia MySQL che PHP abbiano delle funzioncine proprio adatte allo scopo. Rispettivamente INET_NTOA, INET_ATON e long2ip() e ip2long(). PostgreSQL ha addirittura un tipo di dato specifico, se non erro.

Il problema è che nei sistemi a 32bit la funzione PHP ip2long() ritorna un intero SIGNED, spesso negativo, mentre nei sistemi a 64bit torna sempre un UNSIGNED.

Se di questa cosa non te ne accorgi, avrai fatto la colonna della tua tabella come normale INTEGER (dunque SIGNED) e tutti i tuoi test funzioneranno alla grande.

Poi passi in produzione a 64bit e la tabella si riempirà di valori molto vicini a 2^31 (ovvero 127.255.255.255).

Soluzione: il campo della tabella lo devi fare INT(11) UNSIGNED e in tabella dovrai sempre scrivere il valore UNSIGNED; per fare questo, un sistema è usare qualcosa come $ip = sprintf(‘%u’,ip2long($ip)) o qualcos’altro di più veloce con l’operatore shift (mai programmato videogiochi, mai preso confidenza con ‘ste robe arcane);

Nota numero uno: INTEGER UNSIGNED e basta mi pare crei un INT(10), non sufficiente. Meglio specificare INTEGER(11) UNSIGNED.

Nota numero due: usare BIGINT non è consigliabile, perché le INET_* non funzionano con quel tipo di dato.

Comments (View)
blog comments powered by Disqus