Newsgroup: it.comp.www.php
Titolo: un migliore upload file

Salve,
cercavo un codice di upload e gestione di un file, ma, direte voi ce
ne sono migliaia: in effetti ne cercavo uno un po' più raffinato della
media. Mi serve per un progetto nel quale velocità del codice e sua
limitatezza sono un requisito essenziale.
Il file deve essere letto riga per riga (e fin qui),
confrontata ogni riga col risultato di un db {"c'è un numero contenuto
nel file nel db-table pippo?},
estratti i numeri corrispondenti alle righe coincidenti e posti in un
nuovo file.
entrambi vanno salvati in due directory distinte, una di backup e una
di lavoro.
con codice "brutale" posso scriverlo, ma appunto cercavo qualcosa meno
da manuale.
Grazie
Luciano

 lavoro.
non capisco bene cosa c'entra tutto questo con "l'upload"
poi , questa frase non è molto comprensibile:
"Il file deve essere letto riga
 per riga (e fin qui), confrontata ogni riga col risultato di un db {"c'è
 un numero contenuto nel file nel db-table pippo?},"
che vuol dire?
confronti una riga (?) col risultato di un db (????)

Luciano ha scritto:

Qua l'upload non c'azzecca direi
Leggi il file, dalle righe del file estrai gli indici che ti servono e 
li metti in un array. Implodi l'array e lo usi come filtro nella query 
(con IN(1,2,3,4,....) )
con un while del resultset butti fuori i risultati che ti interessano.
Io farei così (sempre che non abbia frainteso il tuo problema)

 - Show quoted text -
Ciao,
Scusate in effetti avevo tralasciato la prima parte (da cui il
titolo): il file proviene da un upload utente. :)
Motosauro, non hai frainteso, credo che tu mi abbia capito...
il problema è questo:
Il file potenzialmente può avere anche 100 o 1000 righe, è per quello
che dovrei trovare una soluzione efficiente per non appesantire o
inchiodare la procedura e far aspettare l'utente.
Mi spiego meglio con l'esempio concreto:
* un utente invia un file con 100 righe (100 numeri di telefono)
* devo controllare quali di questi 100 numeri sono presenti nella
tabella "N" di un db e "quali hanno stato OK"
* quelli presenti, devo salvarli in un file nuovo, e il file
precedente salvarlo per esigenze di log.
* posto che 80 righe (80 numeri) soo OK, devo aggiornare gli 80 record
sulla table N
Un codice "ottimizzato" per fare questa procedura esula dalle mie
conoscenze php, temo di farlo in modo sporco... per questo chiedevo
consiglio!
Grazie
Luciano

Luciano ha scritto:

Beh, intanto comincia col farlo :)
Poi magari i consigli arrivano.
Di base torno a consigliarti:
Leggi le 100 righe, archivia in un array i 100 campi NumeroTelVecchio e 
i 100 campi NumeroTelNuovo (non l'hai specificato, ma presumo che ci 
siano due numeri di telefono per ogni riga, altrimenti la cosa non ha senso)
Se i campi sono numeri di telefono (quindi stringhe) IMHO ti conviene 
fare un loop richiamando una stored-procedure (se hai a disposizione 
MySQL >= 5)
A quel punto alla procedura fai fare:
select id from tabella where numero = @numero AND campoOk = true;
Qui ottieni l'id, quindi
UPDATE tabella set numero = @numeroNuovo where id=@id;
e fai uscire l'id aggiornato per tenere traccia di quello che hai fatto ;)

 - Show quoted text -
Ciao!
Il db è Informix :()
Il formato del file è per ogni riga un numero ed una ricarica da
effettuare.
Allora, quello che ho scritto finora è così (chissà quanti errori ci
sono dentro, spero pochi!):
// PROCEDURA UPLOAD FILE / RICARICA
// File di Prova, formato: telefono;ricarica: es. 123456789;50
$uploaded_file="PROVA.TXT";
//Lettura file
$numeri = array();
$fp1 = fopen($uploaded_file, "r");
if (filesize($fp1) > $MAX_FILE_SIZE) die("File troppo grosso");
if ($fp1) {
    while (!feof($fp1)) {
    	// carica delle linee: verificare bug della 1a linea
        $numeri[] = explode(fgets($fp1, 4096),1)
        	print_r $numeri[];
        $importi[] = implode(fgets($fp1, 4096),2)
        	print_r $importi[]."<BR/>";
    }
    fclose($fp1);
}
// Implodo numeri per formarli per query
$numeri_cs = implode(",", $numeri);
echo $numeri_cs; // 123456789,123456789,123456789
// Query verifica esistenza in db
$query = "Select numeri,stato from sim where numeri in ($numeri_cs);"
echo $query;
?>

 echo $query;
Questo mi pare corretto, ma stai attento a quanti ne processi alla volta, 
perche` la query potrebbe diventare molto pesante.
Fai un po' di test prestazionali.
Bye.

 ?>
Guarda che a mettere una clausola «IN(numero, numero, numero .......)» 
con svariate migliaia di righe ti fa sedere il DataBase ;)
Vai di stored procedures, caching et similia.

Alessandro Pellizzari ,

Alessandro, ok ho utilizzato file():
Per ora sto combattendo con questo:
//Lettura file
//$lines = implode(",", file($uploaded_file));
$lines = file($uploaded_file);
foreach ($lines as $line_num => $line) {
    echo "#{$line_num}: ".$line."<br />\n";
    $numero=explode(";",$line);
    echo "numero: ".$numero[$line_num]."<br/>";
}
però mi stampa solo il primo numero, e poi la seconda stringa, e poi
nulla... :?
Motosauro,
(stored procedure non saprei come farle in informix)...
il problema è che io ho nel file 123456789;50 una volta che ho risolto
il ciclo sopradetto, ed ho di ogni riga il numero e la ricarica,
allora potrei mettere nel ciclo stesso una select e poi un update.. su
quel numero
grazie
Luciano

 nulla... :?
Leggi bene il manuale di explode.
Quando esplodi una stringa come la tua ("12345;67"), avrai solo due indici 
del DB: 0 ("12345") e 1 ("67"). Quindi nella seconda echo dovrai avere 
$numero[0] e non $numero[$line_num]
Bye.

 $numero[0] e non $numero[$line_num]
Infatti, errore risolto, grazie mille.
Il file per ora ha limite 100 righe max.
Dunque l'idea di fare una query e un aggiornamento nel ciclo stesso ti
sembra che possa andare?
grazie
Luciano

 wrote:

Ok, ora l'aspetto del ciclo è qualcosa di più definito:
//Ciclo interr. e aggiornamento DB
foreach ($lines as $line_num => $line) {
    $numero=explode(';',$line,2);
    $ntel = $numero[0];
    $ric = $numero[1];
    $query = 'select count(*) from sim where (ntel='.$ntel.' and
id_sap_ref='.$id_ref.' and tipo_carte=3 and stato=2)';
    echo $query."<br/>";
    $upd = 'update sim set ricarica = '.$ric.' and id_richiesta = '.
$id_rich.' where ntel='.$ntel.')';
    echo $upd."<br/><br/>";
}
sembra ok?
Luciano

 $id_rich.' where ntel='.$ntel.')';
stessa cosa qui:
 ... ricarica = " .intval($ric). " ...
(o floatval se e` decimale). Idem intval per $id_rich, e $ntel come sopra.
E magari anche qualche controllo di validita` della cifra (puo` essere 0, 
minore di 0, superiore a 1000 euro? ecc.)
Bye.


OK. Ti ringrazio fin qui per gli utilissimi consigli.
Una cosa: l'escape equivalente per informix qual è?
Perché il db non è Mysql. (purtroppo?) Non sono riuscito a trovarlo..
Si, sul ntel va fatto un controllo di lunghezza max e di presenza
stringhe. Dovrebbe essere un numero senza il +nn davanti perché per
specifica si suppone sia sempre italiano. Qualche idea con le
espressioni regolari (ne so pochissimo) ?
Grazie.
Luciano

 espressioni regolari (ne so pochissimo) ?
/[0-9]+/
O qualcosa del genere. :) (per esempio /[0-9]{6,13}/ per numeri da 6 a 13 
cifre)
Poi dipende se accetti punti, spazi, barre, trattini o se vuoi toglierli, 
ecc.
Bye.

 Bye.
Si, per l'esattezza (per le mie esigenze) poi la regexp era:
    if (preg_match('/^[0-9]{1,10}$/', $ntel))  {
    //etc
    }
Ora ho un problema: il file che devo esaminare non riesco a gestirlo:
con una Form gestisco l'upload e ho come variabile
    $uploaded_file
Il file .php che prende l'action della form, però mi dà errore. Anche
qui, credo che potrei gestirlo meglio (oltre che senza errori):
// Copia nella dir locale il file e imposta permessi
$temp_name = "ric_temp.txt";
if (!copy($uploaded_file, "./".$temp_name)) {
    die("failed to copy $uploaded_file...\n");
} else {
	$uploaded_file = $temp_name;
}
if (chmod($uploaded_file, 644)) {
	$lines = file($uploaded_file);
}
L'errore è:
Warning: copy(./ric_temp.txt) [function.copy]: failed to open stream:
Permission denied in /home/lgiustini/ggsp/html/Ricarica/file_.php on
line 30
failed to copy /tmp/phpSvqyGg...
perché fallisce la copia? (e qualsiasi altro comando, peraltro...)
Grazie mille come sempre.

 - Mostra testo citato -
Problema risolto!
Luciano