Newsgroup: it.comp.www.php
Titolo: mysql - xls o csv

Sto cercando di creare un file formato foglio elettronico esportando i
dati da mysql con lo script php qui sotto. Tutto funziona a dovere con
poche decine di record ma quando arrivo al centinaio di record
iniziano i problemi (Fatal error: Allowed memory size of 8388608 bytes
exhausted (tried to allocate 2784810 bytes) in
/var/www/lavori/prove/mysql-excel.php on line 73). 
La linea 73 è "$data = str_replace("\r", "", $data);".
Come posso ovviare ?
Grazie. Ilic.
define(db_host, "localhost");
define(db_user, "getsmart");
define(db_pass, "a12270");
define(db_link, mysql_connect(db_host,db_user,db_pass));
define(db_name, "getsmart");
mysql_select_db(db_name);
$select = "SELECT data_scarico, id_ente_operatore AS idente,
prestazioni.id_operatore AS idoperatore, inizio_prestazione,
fine_prestazione, HOUR(inizio_prestazione) AS ore_inizio,
MINUTE(inizio_prestazione) AS minuti_inizio,
SECOND(inizio_prestazione) AS secondi_inizio,
MONTH(inizio_prestazione) AS mese_inizio,
DAYOFMONTH(inizio_prestazione) AS giorno_inizio,
YEAR(inizio_prestazione) AS anno_inizio, WEEKDAY(inizio_prestazione)
AS giornosett, HOUR(fine_prestazione) AS ore_fine,
MINUTE(fine_prestazione) AS minuti_fine, SECOND(fine_prestazione) AS
secondi_fine, MONTH(fine_prestazione) AS mese_fine,
DAYOFMONTH(fine_prestazione) AS giorno_fine, YEAR(fine_prestazione) AS
anno_fine, WEEKDAY(fine_prestazione) AS giornosett, prestazione1,
prestazione2, prestazione3, prestazione4, prestazione5, prestazione6,
prestazione7, prestazione8, prestazione9, prestazione0, nome_ente,
codice_assistito, assistiti.cognome AS cognomeassistito,
assistiti.nome AS nomeassistito, assistiti.codice_fiscale AS
codicefiscaleassistito, assistiti.codice_cma AS cma,
assistiti.indirizzo AS indirizzoassistito, assistiti.disabilitato AS
disabilitatoassistito, codice_operatore, operatori.cognome AS
cognomeoperatore, operatori.nome AS nomeoperatore,
operatori.disabilitato AS disabilitatooperatore FROM prestazioni LEFT
JOIN enti ON 
enti.id
=prestazioni.id_ente_operatore LEFT JOIN assistiti
ON prestazioni.id_ente_assistito=assistiti.ente AND
prestazioni.id_assistito=assistiti.id_assistito LEFT JOIN operatori ON
prestazioni.id_ente_operatore=operatori.ente AND
prestazioni.id_operatore=operatori.id_operatore WHERE
prestazioni.id_ente_operatore='1' AND
(inizio_prestazione<='31-08-2004' AND fine_prestazione>='01-08-2004')
GROUP BY inizio_prestazione, fine_prestazione,
prestazioni.id_operatore, id_ente_operatore, prestazioni.id_assistito
ORDER BY inizio_prestazione";				
$export = mysql_query($select);
$count = mysql_num_fields($export);
for ($i = 0; $i < $count; $i++) {
	$header .= mysql_field_name($export, $i)."\t";
}
while($row = mysql_fetch_row($export)) {
	$line = '';
	foreach($row as $value) {
		if ((!isset($value)) OR ($value == "")) {
			$value = "\t";
		} else {
			$value = str_replace('"', '""', $value);
			$value = '"' . $value . '"' . "\t";
		}
		$line .= $value;
	}
	$data .= trim($line)."\n";
}
$data = str_replace("\r", "", $data);
if ($data == "") {
	$data = "\n(0) Records Found!\n";
}
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=spreadsheet.xls");
header("Pragma: no-cache");
header("Expires: 0");
print "$header\n$data";

 header("Content-Disposition: attachment; filename=spreadsheet.xls");
i dati escono (o dovrebbero) in formato csv
in un corretto schema i campi dovrebbero essere inclusi fra " " (doppi
apici) delimitati da , o ; le linee terminate da \n

 
Secondo me l'errore non sta tanto nella query lunga, quanto nel risultato.
La variabile $data a un certo punto diventa cosě grande che da sola non 
riesce a contenere tutti i dati (anche io ebbi lo stesso problema con un 
mega array risultanta da una query).
La soluzione potrebbe essere questa: metti un limite alla query e per 
ogni pezzo fai una variabile diversa.
In questo modo farai piů di una query e le variabili diventano tante, ma 
almeno non dovresti avere problemi di dimensione.
Oppure, visto che la query ce la fa ad eseguirla, non fare una sola 
variabile $data ma fanne tante, ad esempio ogni 50 record.
Non penso ci siano limiti di peso con tante variabili.
-- 
Andrea Azzini
Arya Interactive Media srl
http://www.inarya.com

 Non penso ci siano limiti di peso con tante variabili.
Purtroppo si, 8 Mb è la dimensione massima del singolo processo php.
Ho scrive il file pezzo per volta, svuotando la variabile di volta in 
volta oppure cambia il valore della variabile memory_limit in php.ini.
Tac

 volta oppure cambia il valore della variabile memory_limit in php.ini.
Parse error on line 2. "O" expected.
Tac

 
premetto che non ho letto il tuo codice nel dettaglio.. ma ho visto gli
altri messaggi..
questo dovrebbe ovviare il tuo problema.. però non è una soluzione ottimale
(soprattutto non è assolutamente testata).. e ti consiglio vivamente di
cambiare quella query!!
$export = mysql_query($select);
if(mysql_num_rows($export)>0){
    header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=spreadsheet.xls");
    header("Pragma: no-cache");
    header("Expires: 0");
 
    $count = mysql_num_fields($export);
    for($i = 0; $i < $count; $i++)
        $header .= mysql_field_name($export, $i)."\t";
    print "$header";    
while($row = mysql_fetch_row($export)) {
    $line = '';
    foreach($row as $value){
        if((!isset($value)) OR ($value == ""))
            $value = "\t";
        else{
            $value = str_replace('"', '""', $value);
            $value = '"' . $value . '"' . "\t";
        }
        $line .= $value;
    }
    print "\n" . trim($line);
    }
}
else 
    echo "\nRecords not found!\n";
-- 
www.iuz-lab.info

 cambiare quella query!!
Oh bella, perchè mai?
Tac

apici) delimitati da , o ; le linee terminate da \n
Cosa c'entra ?

Non penso ci siano limiti di peso con tante variabili.
Tentar non nuoce... E si prima che a fare calcoli.
Grazie. Ilic.

Purtroppo si, 8 Mb č la dimensione massima del singolo processo php.
Va bhe... Ho tagliato la testa al toro e ho raddoppiato la memoria
massima ai processi php (come nella miglior tradizione per i
programmatori mediocri).
;-)
Facile e veloce. In fondo č cosě che va avanti la new economy, no ?!
Grazie a tutti. Ilic.

 Facile e veloce. In fondo è così che va avanti la new economy, no ?!
Se non ricordo male anche la Microsoft ha una politica simile ;-).
Tac


:Provate a guardare gli ingredienti del famoso Labello che si usa per
:le labbra screpolate: Butirrospermum Parkii (sperma di maiale).

Se non ricordo male anche la Microsoft ha una politica simile ;-).
Appunto  :-(
Alla fine abbiamo dell'ottimo hardware e del pessimo software.
Per non parlare dei sistemi operativi che ormai prevedono l'utilizzo
di qualsiasi periferica esistente al mondo ma si inchiodano se scrivi
un file di testo.
:-)

O mi e' sfuggita qualche cosa?
Si. Ti è sfuggito che non ho mica capito cosa intendi.
Spiegami meglio.
Grazie. Ilic.

Cosa devo fare ?
Qualcosa di questo tipo, senza salvare i dati in memoria mentre li leggi,
ma sparandoli su una handle temporanea, sulla quale poi farai un rewind()
...e poi la passi direttamente a PHP che la dia in bocca al webserver.
$export = mysql_query($select);
$rows	= mysql_num_rows($export);
if (0 == $rows)
{
	die("0 records.");
}
$count	= mysql_num_fields($export);
$tr	= array(
	'"'	=> '""',
	"\r"	=> '',
);
$fp	= tmpfile();	// Creo handle temporanea
$tab	= '';
$hdr	= '';
for ($i = 0; $i < $count; $i++)
{
	$hdr	.= $tab . mysql_field_name($export, $i);
	$tab	= "\t";
}
fwrite($fp, "$hdr\n");	// Scrivo roba nella handle
while($row = mysql_fetch_array($export))
{
	$tab	= '';
	$line	= '';
	for ($f = 0; $f < $count; $f++)
	{
		if (''	!= ($val = strtr($row[$f], $tr)))
			$val = "\"$val\"";
		$line	.= $tab . $val;
		$tab	= "\t";
	}
	fwrite($fp, "$line\n";
}
mysql_free($export); // Non ricordo se si chiama mysql_free o 
$size	= ftell($fp);	// Quanti byte nel buffer?
rewind($fp);		// Ritorna all'inizio del buffer
Header("Content-type: application/octet-stream");
Header("Content-Disposition: attachment; filename=spreadsheet.xls");
Header("Content-Length: $size");	// Si dice quant'e' lungo
Header("Pragma: no-cache");
Header("Expires: 0");
// Se il sistema lo supporta, questo ai CSV ni mette 'r turbo
// (costa qualcosa in CPU)
ob_start('ob_gzhandler');
// IN ALTERNATIVA e forse meglio di ob_start:
// ini_set('zlib.output_compression', 8192);
fpassthru($fp);		// Passa il buffer a PHP / Apache
