Newsgroup: it.comp.www.php
Titolo: Errori warning - come evitarli?

Buongiorno!
Qualche mese fa ho realizzato una piccola applicazione PHP per acquisire 
richiesta RMA per l'azienda per cui lavoro.
Ora, dopo tre mesi di rinvii, l'azienda ha deciso di far partire il 
servizio.
Purtroppo cominciano i problemi con il provider dove ho acquistato lo spazio 
per il sito.
Vorrei confrontarmi con voi esperti dell'ambiente PHP e suppongo delle 
tematiche generali dei web server per capire perchè con questo provider ho 
problemi.
Alla fine vorrei capire se la mia applicazione è proprio da buttare o se il 
servizio acquistato è carente.
Cercherò di essere breve. :-)
L'applicazione, la mia prima realizzata in PHP, così è comprensibile anche 
il mio grado di esperienza del linguaggio, è stata sviluppata su un pc xp 
con Apache 2, MySQL5 e PHP 5.
Dopo lo sviluppo è stata testata su un web server gratuito e non ho mai 
avuto nessun problema di sorta, ma proprio nessuno!
L'applicazione funzionava come volevo io, era sufficientemente veloce, 
insomma ero soddisfatto.
Terminata la fase di test a ottobre ho scelto un web server (non italiano) 
con i servizi adeguati e ho installato la mia applicazione.
Diciamo che la prima installazione non è stata così facile come 
l'installazione sul web server gratuito, ma dopo qualche mail con il tecnico 
l'applicazione funzionava come previsto.
Poi a novembre l'azienda decide che è meglio iniziare il servizio nel 2008 
e, salvo aggiornare quotidianamente il database, il sito e l'applicazione 
non viene più utilizzata, nè modificata.
La scorsa settimana, finalmente, l'azienda decide di partire, faccio la 
prima connessione al mio sito e ricevo le seguenti segnalazioni :
Warning: session_start() [function.session-start]: Cannot send session 
cookie - headers already sent by (output started at
/home/domains/
dominio.it/public_html/login.php:12
) in 
/home/domains/
dominio.it/public_html/loginmain.php
 on line 14
Warning: session_start() [function.session-start]: Cannot send session cache 
limiter - headers already sent (output started at
/home/domains/
dominio.it/public_html/login.php:12
) in 
/home/domains/
dominio.it/public_html/loginmain.php
 on line 14
e poi viene emessa la pagina.
Purtroppo la segnalazione citata è solo la prima, se vado anche in altre 
pagine posso ricevere segnalazioni del tipo
Warning: Cannot modify header information - headers already sent by (output 
started at
/home/domains/
dominio.it/public_html/registrazione.php:12
) in 
/home/domains/
dominio.it/public_html/registrazionemain.php
 on line 29
Insomma diventa impossibile usare l'applicazione.
Però ora il provider mi dice che il loro server e configurato correttamente, 
e non posso discutere, ma la mia applicazione che non è più  stata 
modificata dall'estate scorsa e che fino ad novembre funzionava sul loro 
server, non è più utilizzabile.
Dove posso sbattere la testa per evitare di vedere quelle segnalazioni?
Di seguito pubblico il codice se può essere utile.
Abbiate pietà se vedete sciocchezze. :-)))
Grazie. :-)
********************************************************************************
Pagina iniziale (Login.php) ********************
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>RMA - Accesso</title>
<link rel="stylesheet" type="text/css" href="stylerma.css">
</head>
<body>
<?php  include("loginmain.php"); ?>     ***** (questa è la riga 12) ******
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<div id="pagina">
     <div id="testa">
       <a href="
http://www.dominio.it
"><img class='img' 
src="images/Logo.jpg"><img class='img'
src="images/LogoEstensione.jpg"></a>
    </div>
     <div id='corpo'>
        <div id='corposx200'></div>
       <div id='corpocn598'>
           <div class='centitolo' style='font-weight: bold; text-align: 
left; vertical-align: middle;'>
           <div class="avtesto">
              Benvenuto nel Centro Assistenza <br><br>
           Inserisci le chiavi di accesso per creare una
nuova richiesta di R.M.A. <br>
         </div>
           </div>
           <div class='cenriga'></div>
           <div class='cenriga240'>Codice Cliente: &nbsp </div>
      <div class='cenriga358'><input class='acc' name='CodiceCliente' 
size='20' maxlength='12'
type='text' value='<?php print isset($_POST["CodiceCliente"]) ? 
$_POST["CodiceCliente"] : "" ?>'></div>
      <div class='cenriga240'>Codice Destinazione: &nbsp </div>
      <div class='cenriga358'><input class='acc' name='CodiceDestin' 
size='20' maxlength='5'
type='text' value='<?php print isset($_POST["CodiceDestin"]) ? 
$_POST["CodiceDestin"] : "" ?>'></div>
           <div class='cenriga240'>Password: &nbsp </div>
      <div class='cenriga358' ><input class='acc' name='Password' size='20' 
maxlength='20'
type='password' value='<?php print isset($_POST["Password"]) ? 
$_POST["Password"] : "" ?>'></div>
           <div class='cenriga'></div>
      <div class='cenriga240'></div>
           <div class='cenriga358'>
                <input name='seen_already' type='hidden' value='hidden_data' 
/>
                <input name='opzione' type='submit' value='Conferma'>
       </div>
           <div class='cenriga'></div>
            <div class='cenriga'>
           <div class="link" style="width: 40%; text-align: right;"><a
href='registrazione.php'>Registrati</a></div>
           <div class="link" style="width: 10%;"> &nbsp </div>
           <div class="link" style="width: 50%; text-align: left;"><a
href='richpassword.php'>Hai dimenticato la password?</a></div>
      </div>
      <div class='cenriga' style="color: red; text-align: center; font-size: 
14px; font-weight:
bold;"><?php print $descr[1]; ?></div>
       </div>
       <div id='corpodx200'></div>
     </div>
     <div id="piede">
        <div id="distpiede">&nbsp;</div>
         <div id="bannerpiede">
        <a href="
http://www.dominio.it
"><img class="img"
src="images/Trade_product_banner2.gif"></a>
     </div>
       <div id="firmapiede">
          <div class="avtesto" style="margin-top: auto;">© (2007)</div>
     </div>
    </div>
</div>
</form>
</body>
</html>
loginmain.php ******************
<?php
#-------------------------------------------------------------------------------
# Inclusioni
#-------------------------------------------------------------------------------
include("openconndb.php");
include("statosessione.php");
include("loginctrl.php");
#-------------------------------------------------------------------------------
# Verifica se attivo l'aggiornamento del database
StatoAggiornamento();
# Avvia la sessione
session_start();     ****** questa è la riga 14 ************
# Apre la Connessione al database
OpenConnDB();
$descr = array();
$descr = array_fill(1, 10, "");
$CtrlLogin = new LoginCtrl();
if(isset($_POST["seen_already"])) {
   $descr = $CtrlLogin -> Controllo_Dati($_POST['CodiceCliente'], 
$_POST["CodiceDestin"], $_POST["Password"], $descr);
   if($descr[0] == false) {
    $_SESSION['azienda']= "900";
   $_SESSION['codicecliente'] = $_POST['CodiceCliente'];
   $_SESSION['codicedestin'] = $_POST['CodiceDestin'];
     header("Location: menurma.php");
   }
}
?>
openconndb.php ***************************
<?php
function OpenConnDB () {
  $connection = mysql_connect("Localhost", "user","password")
                or die("Impossibile connettersi al server.");
  $db = mysql_select_db("mioDB", $connection)
        or die("Impossibile selezionare il database.");
}
?>
statosessione.php *****************************
<?php
#-------------------------------------------------------------------------------
# Verifica la sessione
#-------------------------------------------------------------------------------
function StatoSessione () {
   session_start();
   if($_SESSION['codicecliente'] <= "" or $_SESSION['codicedestin'] <="" ) {
     header("Location: login.php");
  }
}
#-------------------------------------------------------------------------------
# Verifica se sono attive procedure di aggiornamento del database
#-------------------------------------------------------------------------------
function StatoAggiornamento() {
   # Apre la Connessione al database
   OpenConnDB();
   $importazione = 0;
   $esportazione = 0;
  $query  = "select *  from aggiornamenti ";
  $query .= "where applicazione = 1 ";
   $result = mysql_query($query) or die("Impossibile eseguire la 
selezione.". mysql_error());
   $righelette = mysql_num_rows($result);
  if($righelette > 0){
     while($riga = mysql_fetch_array($result)) {
           $importazione = $riga["Importazione"];
           $esportazione = $riga["Esportazione"];
        break;
    }
  }
  if($importazione == 1 or $esportazione == 1){
    header("Location: manutenzione.php");
   return true;
  }else{
    return false;
  }
}
#-------------------------------------------------------------------------------
?>
loginctrl.php ******************************
<?php
Class LoginCtrl {
#-------------------------------------------------------------------------------
# Controllo_Dati
#-------------------------------------------------------------------------------
  function Controllo_Dati($codicecliente, $codicedestin, $password, $descr) 
{
    $descr[0] = false;
   $query  = "Select *, uncompress(PwdCliente) as pwduc From utenti ";
   $query .= "Where CodiceCliente = '".
             mysql_real_escape_string($_POST["CodiceCliente"]). "' ";
   $query .= "  and CodiceDestin = '".
             mysql_real_escape_string($_POST["CodiceDestin"]). "' ";
   $result = mysql_query($query)
             or die("Impossibile eseguire la selezione.". mysql_error());
   $RigheLette = mysql_num_rows($result);
   if($RigheLette > 0) {
      while ($riga = mysql_fetch_array($result)) {
     /* Se non esiste la Data Conferma, l'accesso non dev'essere consentito 
*/
     if(empty($riga ['DataConferma']) == true)  {
          $descr[0] = true;
         $descr[1] = "* Accesso non ancora abilitato.";
     } else {
         /* Controlla la Password */
         if($riga ['pwduc'] !=  $_POST["Password"]) {
           $descr[0] = true;
             $descr[1] = "* Password errata.";
       }
           }
     }
   } else {
      $descr[0] = true;
        $descr[1] = "* Codice Cliente o Codice Destinazione inesistente.";
  }
 mysql_free_result($result);
 return($descr);
  }
}
?>
******************************************
Il provider mi suggeriva di anteporre il carattere @ a session start(), ed 
in effetti i messaggi iniziali non vengono più emessi, ma se passo ad una 
pagina successiva e poi torno a login.php ricevo la seguente segnalazione :
Warning: Cannot modify header information - headers already sent by (output 
started at
/home/domains/
dominio.it/public_html/registrazione.php:12
) in 
/home/domains/
dominio.it/public_html/registrazionemain.php
 on line 29
In questo caso la riga 29 è
header("Location: login.php");
Cosa devo modificare?
Grazie
Ciao
Eugenio 

 session cookie - headers already sent by (output started at
Inserisci all'inzio (come prima riga) nei tuoi script il seguente
codice:
<?php ob_start(); ?>
Oppure abilita la direttiva output_buffering tramite .htaccess (se
possibile).
-- 
Vuoi distribuire il tuo sito web su CD/DVD?
Prova 
http://www.dwebpro.com/
Vuoi diventare un esperto analista PHP/MySQL?
Vieni a fare uno stage con noi: 
http://www.creativepark.it/stage/

 
Il problema è legato alla diversa configurazione del php, nel tuo caso 
le fasi sono invertite! Teoricamente dovresti avere la cfg di sviluppo 
con la visualizzazione (a vidio, su file, come preferisci) di tutti i 
tipi di errore, mentre nella fase di produzione questo viene oscurato 
(attraverso mex di errore potresti scoprire delle vulnerabilità del 
software)
Hai due soluzioni: modifichi il codice alla ricerca degli errori 
(consigliato) oppure cambi, se puoi, le impostazioni sulla 
visualizzazione degli errori sul server di produzione; ovviamente è come 
spazzare il salotto e mettere la polvere sotto il tappeto!
Se include("loginmain.php");  apre la sessione si trova in output gli 
header della tua pagina e dà l' Warning: Cannot modify header 
information - headers already sent by ..
Vedi sul man: 
http://it2.php.net/manual/en/ref.errorfunc.php
	Francesco

 
In questo modo raggiri il problema, ma non lo risolvi! Alla fine non è 
impossibile includere come prima riga dello script tutto ciò che 
riguarda gli header e poi procedere con la pagina html...
	Francesco

 <?php  include("loginmain.php"); ?>     ***** (questa è la riga 12)
E qui mandi il cookie, che pero` non puo` essere mandato perche` hai gia` 
inviato output.
Devi inviare il cookie (quindi includere quel file o comunque il file che 
lo invia) PRIMA di qualsiasi altro carattere, anche un solo spazio.
Tutte le tue pagine devono iniziare con:
<?php
include("file che gestisce le sessioni e i cookie.php");
?>
<!DOCTYPE ...>
Probabilmente in locale hai l'output buffering attivo e non te ne accorgi.
Bye.

 In questo modo raggiri il problema, ma non lo risolvi!
Dipende da cosa si intende per raggirare e risolvere. Utilizzare
l'output buffering (un funzione nativa del PHP) per gestire il problema
degli header a me non sembre un raggiro.
Oltretutto l'output buffering e' utile nel passo successivo, quello
della gestione degli errori. In una applicazione in cui non viene
separata la logica applicativa da quella di presentazione (come quella
di Eugenio), l'output buffer e' necessario (se non l'unica scelta
possibile) per posticipare l'invio dei dati in modo da poter
intercettare gli errori e visualizzare dei messaggi "ben formattati".
Se poi Eugenio, con l'esperienza, inizia a capire meglio il protocollo
HTTP, il funzionamento di PHP, e l'architettura delle applicazioni web
(es. il pattern MVC), allora potra' disabilitare l'output buffering ed
iniziare a sviluppare delle applicazioni che non lo richiedano per la
gestione del problema degli header.


 
Non voglio certo polemizzare, ma la mia risposta era contestualizzata 
all'esempio di Eugenio, una situazione specifica, e non in generale.
Nel caso esposto, è consigliabile mettere l'apertura della sessione come 
prima azione e poi procedere all'output della pagina (bufferizzata 
oppure no)
Resta valida la tua osservazione sull'output bufferizzato per eventuali 
messaggi di errore oppure il consiglio di separare l'applicazione dalla 
presentazione, ma questo è un altro ambito.
	Francesco

 (bufferizzata oppure no)
E per gli header location (vedi riga 29 di registrazionemain.php)? 


Grazie a tutti per le spiegazioni.
Ora ho compreso il funzionamento.
In effetti gli errori non vengono più segnalati.
A volte sarebbe meglio che certi default non fossero mai attivi.
Ora però ho difficoltà a comprendere la seconda segnalazione:
Warning: Cannot modify header information - headers already sent by (output 
started at /home/domains/
dominio.it/public_html/statosessione.php:47
) in 
/home/domains/
dominio.it/public_html/registrazionemain.php
 on line 29
Dalla pagina di Login, cliccando su "Registrati", accedo alla pagina di 
registrazione "Registrazione.php".
Se però rinuncio alla registrazione e clicco su un pulsante "Esci" mi viene 
emessa la suddetta segnalazione.
Qui di seguito gli script:
Registrazione.php ****************
<?php  include("registrazionemain.php"); ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>RMA - Registrazione</title>
<link rel="stylesheet" type="text/css" href="stylerma.css"/>
</head>
<body>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<div id="pagina">
     <div id="Testa">
         <a href="
http://www.dominio.it
"><img class='img' 
src="images/Logo.jpg"><img class='img' src="images/LogoEstensione.jpg"></a>
    </div>
...
Resto del codice HTML ...
...
     <div id='corpo'>
             <div class='cenriga448'  style='text-align: left;'>
                  <input name='seen_already' type='hidden' 
value='hidden_data'>
                  <input name='opzione' type='submit' value='Conferma'>
                  <input name='annulla' type='reset' value='Annulla'>
                  <input name='opzione' type='submit' value='Esci'>
       </div>
          </div>
   </div>
</div>
</form>
</body>
</html>
Registrazionemain.php ********************
<?php
#-------------------------------------------------------------------------------
# Inclusioni
#-------------------------------------------------------------------------------
include("openconndb.php");
include("statosessione.php");
include("ctrlemailstr.php");
include("registrazionectrl.php");
include("registrazionectrlerr.php");
include("inviamailconf.php");
include("riferimentiuteattiv.php");
include("riferimentiazienda.php");
#-------------------------------------------------------------------------------
# Verifica se attivo l'aggiornamento del database
StatoAggiornamento();
/* Apre la Connessione al database */
OpenConnDB();
$descr = array();
$descr = array_fill(1, 20, "");
$CtrlReg = new RegistrazioneCtrl();
if(isset($_POST["seen_already"])) {
   if($_POST["opzione"] == "Esci"){
     header("Location: login.php");      *********** questa è la riga 29 
**************
  } else {
      $descr = $CtrlReg -> Controllo_Dati($_POST["CodiceCliente"], 
$_POST["CodiceDestin"], $_POST["Password"], $_POST["PasswordC"], 
$_POST["Email"], $_POST["EmailC"], $descr);
      if($descr[0] == false) {
         $CtrlReg -> Registra($_POST["CodiceCliente"], 
$_POST["CodiceDestin"], $_POST["Password"], $_POST["PasswordC"], 
$_POST["Email"], $_POST["EmailC"]);
         InviaMailConf($descr);
     if($descr[0] == false) {
           header("Location: registrazionemail.php");
     }
     }
    }
}
?>
Statosessione.php ***********************************







}
?> ********* questa è riga 47 *************
Quindi cliccando su "Pagina Login / Registrati" accedo alla pagina di 
Registrazione che esegue inizialmente lo script "registrazionemain.php", ma 
che di fatto non farà nulla, salvo aprire la connessione al db provocato da 
"Statosessione.php".
Solo ora vedo un inutile doppia apertura del DB, ma non mi pare sia la causa 
della segnalazione.
Però se clicco su "Esci" non capisco, o meglio non vedo, perchè devo 
ricevere la segnalazione specifica all'inizio.
L'unico output che viene provocato non è quello specificato dalla riga 29 di 
"registrazionemain.php" ovvero
header("Location: login.php");  ?
Che cosa c'entra in questo caso "Statosessione.php"?
Grazie
Ciao
Eugenio
 

 E per gli header location (vedi riga 29 di registrazionemain.php)?
In effetti ora ho questo problema (vedi mio nuovo post).  :-)
Leggendo il tuo precedente post ho letto:
"In una applicazione in cui non viene
separata la logica applicativa da quella di presentazione (come quella
di Eugenio), "
Mi puoi fornire un link da cui posso comprendere meglio, magari con esempi, 
che cosa s'intende?
Grazie
Ciao
Eugenio

 E per gli header location (vedi riga 29 di registrazionemain.php)? 
La tua mail è valida? In tal caso ti rispondo lì, altrimenti mi astengo!
	Francesco


Si, grazie.
Ciao. 

 esempi, che cosa s'intende?
Anche se non tratta di PHP:
http://www.microsoft.com/italy/msdn/risorsemsdn/architetti/pragmatica.ms
px
Questo parla di PHP (Smarty):
http://www.smarty.net/manual/it/what.is.smarty.php
Breve spiegazione del pattern MVC in PHP
http://www.tonymarston.net/php-mysql/model-view-controller.html


"Filippo Toso - Creative Park"  ha scritto nel messaggio > Eugenio ha 

Grazie!
Ciao
Eugenio

 A volte sarebbe meglio che certi default non fossero mai attivi.
[..]
Senza offesa, niente di personale.
A volte, invece, sarebbe opportuno che chi fa il programmatore (parli di 
una realtà professionale) sia effettivamente un programmatore.
Non esiste portare in produzione un software scritto da chi non conosce 
il linguaggio. Programmare decentemente richiede **ANNI** di studio 
mirato, il resto è "cazzeggiare".
Del resto, non accetteresti mai che il tuo dentista ti dicesse "tu 
intanto apri la bocca, il dente te lo anestetizza mio figlio, studia 
giurisprudenza e naturalmente è la prima volta che lo fa. Tu rilassati".
I quesiti che hai posto sono davvero "base", a cominciare dal fatto che 
- e questo a PRESCINDERE COMPLETAMENTE DAL PHP - uno sviluppatore SA 
perfettamente che problemi incontrerà sviluppando su una piattaforma e 
testando su una diversa.
E siccome li sa, smettono di essere sorprese ed imprevisti. ;)
ciao, f.

 gestione del problema degli header.
No, non ed ancora no, prima si impara a programmare, poi ci si fa pagare 
per farlo.
ciao, f.

 pagare per farlo.
Pensavo stessimo parlando del problema degli header nell'applicazione
di  Eugenio, mi sono perso qualcosa?


 ciao, f.
Io invece qualcosa di personale da dirti l'avrei.
E dopo tutta questa filippica cosa mi vuoi dire?
Che ti ho rubato il pane di bocca?
Io credo che un programmatore migliora, oltre che con lo studio, soprattutto 
con tanta pratica e seguendo i consigli dei più esperti.
Sì, è il mio primo lavoro in PHP, sarà sicuramente il peggiore tra tutti 
quelli sviluppati da ogni partecipante di questo NG.
Ma cosa vuoi?
Ne vado orgoglioso e non sarà certo l'essere stato "costretto" 
all'inserimento di
<?php ob_start(); ?>
come ha consigliato Filippo Toso ad abbattermi.
Resto comunque terribilmente orgoglioso del mio "cazzeggio".
Ho realizzato la mia prima applicazione PHP.
So che alla prossima (semmai avrò occasione di svilupparla) terrò conto di 
quanto mi hanno consigliato Filippo, Francesco e Alessandro, perchè hanno 
aggiunto qualcosa in più alla mia conoscenza, fatta seguendo corsi on-line e 
manuali di PHP che si trovano in commercio.
Sono autodidatta!
Guarda caso per il mio primo lavoro ho seguito gli esempi dei corsi e testi 
acquistati.
Non avendo a disposizione un "nato imparato" come te,  mi devo accontentare 
di quel che passa il convento.
Continua pure con i tuoi sermoni, filippiche e reprimende.
Hai un futuro, hai ancora **ANNI** davanti a te come solone informatico.
Il fatto è che da te non ho imparato nulla, ma proprio nulla.
Comunque, sono un buono, ti voglio dare una possibilità: se vuoi farmi un 
corso gratis, sono disponibile, contattami pure.
Purchè sia gratis! ;-)
Ciao signorsotuttoio

 quelli sviluppati da ogni partecipante di questo NG.
Eh, mai dire mai...

 di  Eugenio, mi sono perso qualcosa?
Si ;), facevo un discorso più in generale. ;)
ciao, f.

 ;), ma con l'aggiunta di un "e ora che lo sai, non farlo mai più".
Ti suggerisco di rileggere il tuo post (
http://tinyurl.com/2lydu4
),
perche' mi risulta difficile credere che Eugenio lo abbia intepretato
come un suggerimento.
