[PHP] Guestbook

Stato
Discussione chiusa ad ulteriori risposte.
A

asder99

Guestbook in php. Qualche consiglio?

Codice:
<?php
	class Guestbook {
		public $con;
		public $titolo;
		public $nick;
		public $testo;
		
		// Costruttore
		public function __construct($tit, $nic, $tes) {
			$this -> con = @new mysqli("localhost", "root", "", "sito");
			if(mysqli_connect_errno() != 0) {
				print "<td width='700'>Connection failed (" . mysqli_connect_errno() . "): " . mysqli_connect_error() . "</td>";
			}
			$this -> titolo = $tit;
			$this -> nick   = $nic;
			$this -> testo  = $tes;
			$this -> control_all($titolo, $nick, $testo);
			$this -> control_tit($titolo);
			$this -> control_nic($nick);
			$this -> control_tes($testo);
			$this -> con -> query("SET NAMES 'uft8'");
			$this -> insert($titolo, $nick, $testo);
			$this -> view();
		}
		
		// Controllo che non ci siano variabili vuote
		public function control_all($titolo, $nick, $testo) {
			if(!$this->titolo or !$this->nick or !$this->testo) {
				print "<td>Input incompleto</td>" and die;
			}
		}
			
		// Controllo che le varibili siano solo lettere e numeri
		public function control_tit($titolo) {
			if(!preg_match("/^[a-z]{3,20}$/", $this -> titolo)) {
				print "<td>Input errato</td>" and die;
			}
		}
		
		// Controllo che le varibili siano solo lettere e numeri
		public function control_nic($nick) {
			if(!preg_match("/^[a-z]{3,10}$/", $this -> nick)) {
				print "<td>Input errato</td>" and die;
			}
		}
		
		// Controllo che le varibili siano solo lettere e numeri
		public function control_tes($testo) {
			if(!preg_match("/^[a-z]{3,500}$/", $this -> testo)) {
				print "<td>Input errato</td>" and die;
			}
		}
		
		// Inserisco i dati nel database
		public function insert($titolo, $nick, $testo) {
			$query = "INSERT INTO guest(titolo, nick, testo) VALUES('$this->titolo','$this->nick','$this->testo')";
			$result = @$this -> con -> query($query);
			if($result === FALSE) {
				print "<td>Query Fallita</td>" and die;
			}	
		}
		
		// Mostro i dati
		public function view() {
			$query = "SELECT * FROM guest ORDER BY id DESC";
			$result = @$this -> con -> query($query);
			if($result === FALSE) {
				print "<td>Query Fallita</td>" and die;
			}	
			while(($row = @$result -> fetch_assoc()) !== NULL) {
				print "<tr>{$row['titolo']}  {$row['nick']}  {$row['testo']}</tr>";
			}
		}
	
	
	}
?>
 
Non ho guardato attentamente il sorgente perché secondo me usare il db per un guestbook è uno spreco di query/banda...
Se vuoi un consiglio usa un file XML esterno per memorizzare il tutto (ovviamente col PHP mantieni i controlli sugli input).
Poi, potresti aggiungere un controllo sull'IP per eventuali BAN ed inoltre potresti limitare (con pause di pochi secondi) l'inserimento di post da parte di uno stesso utente/IP in successione (meglio evitare attacchi DoS xD).
 
io invece opto per il db... comunque il guestbook è mal progettato, e se uno vuole visualizzare i messaggi senza inserirne uno? Poi continuate a dichiarare tutto public...
 
Apparte il guestbook io volevo qualche consiglio sul codice oop dopo che non è fatto benissimo lo so.
Poi il fatto di non usare il db per spreco di query/banda omg, se lo upperò in futuro il db effettuerà si e no 2 query l'anno lol
 
non c'è molto da dire... posso capire se lo hai fatto per esercitarti, ma comunque io te l'ho detto: Dichiari tutto "public", mentre l'unica cosa public da dichiarare li era la classe costruttrice.
 
L'OOP non è il massimo. Gli attributi sono tutti pubblici... per superare i controlli che hai messo mi basta fare
Codice:
$g = new Guestbook("a", "b", "c");
$g->titolo = "";
$g->nick = "";
$g->testo = "":
$g->insert();
quindi gli attributi vanno resi privati. Inoltre, la stessa cosa vale per le funzioni di controllo, visto che hanno un senso solo e soltanto all'interno della classe e sono utilizzate solo in quel contesto.
Inoltre il controllo dentro al costruttore è prettamente inutile, va fatto dentro la funzione insert. Vedi l'esempio di prima, se avevi fatto il controllo d'integrità all'interno di insert quel codice avrebbe funzionato come ci si aspettava. Invece in quel caso basta poco per bypassare il controllo. Resta comunque buona norma incapsulare i dati.
#edit ho visto soltanto adesso le chiamate all'interno del costruttore, sono sbagliate. Uno magari vuole fare l'inserimento, o solo la visualizzazione, mentre tu gliele dai entrambe senza possibilità di scelta. Insomma, quel costruttore è completamente errato.
 
Quindi rendendo tutto private tranne il costruttore, il controllo non è bypassabile giusto?
 
No devi rendere tutto privato tranne il costruttore, la funzione insert e la funzione view. Inoltre il costruttore è da riscrivere per il motivo che ti ho specificato nell'edit di sopra.
 
Scusa se utilizzo la classe con questo esempio:

Codice:
<?php

$g = new Guestbook("a", "b", "c");

?>

Potrei rendere tutto private tranne il costruttore..
 
asder99 ha detto:
Scusa se utilizzo la classe con questo esempio:

Codice:
<?php

$g = new Guestbook("a", "b", "c");

?>

Potrei rendere tutto private tranne il costruttore..

Ho capito ma è sbagliato. Poi fai come ti pare. Puoi lasciarla anche così com'è.
Magari uno vuole fare l'inserimento, e poi visualizzare i dati dopo.. invece tu lo fai fare in contemporanea. Inoltre uno potrebbe anche soltanto visualizzare ma non inserire.
Il fatto è che scommetto che tu questa classe non l'hai usata. Perchè se l'avessi usata ti saresti reso conto che è impossibile soltanto visualizzare i dati per come l'hai scritta. Ma devi per forza inserire qualcosa...
 
Non ho provato nulla, oggi pomeriggio ho studiato un po di oop e ho buttato giù questa classe.
 
scusa stoner, ma io che ho detto? :D

comunque usa gli switch.

switch ($_GET["act"])
{
case 'insert': $this->inserisci_commento(); // non mi ricordo il nome del metodo
break;

default: $this->visualizza_commenti(); // non mi ricordo il nome del metodo
break;
}
 
CrAzY ha detto:
Non ho guardato attentamente il sorgente perché secondo me usare il db per un guestbook è uno spreco di query/banda...
Se vuoi un consiglio usa un file XML esterno per memorizzare il tutto (ovviamente col PHP mantieni i controlli sugli input).
Rispondo a te per tutti quelli che han detto che è uno spreco usare un database.
XML è più lento (devi leggere il file, parsarlo, e tenerlo in memoria), meno affidabile (o meglio, SimpleXML è sicuramente meno affidabile di MySQLi), e più difficile da usare rispetto ad un database. Non è uno spreco in nessun modo la vedi, anzi.
CrAzY ha detto:
Poi, potresti aggiungere un controllo sull'IP per eventuali BAN ed inoltre potresti limitare (con pause di pochi secondi) l'inserimento di post da parte di uno stesso utente/IP in successione (meglio evitare attacchi DoS xD).
Vero.
Per far questo, ti basta creare una tabella (o integrare in quella già esistente) in cui stori ip/data di post, e poi verificare che lòa data del post sommata al timeout deciso non superi la data attuale.
stoner ha detto:
Il tuo post è esatto.. in parte.
Nel senso che è impeccabile se si adotta la visione dell'OOP portata in auge dal C++; questa visione però è, a mio modo di vedere, errata, e mi piacerebbe spiegare il perché.

E' il classico ragionamento inculcato da C++; e cioè "quando scrivi una classe, sei in guerra con chi la userà".
Ora, quando in C++ è un approccio che potrebbe durare a una discussione superficiale, in PHP perde completamentre significato.
Perché, a differenza di C++, in PHP usando una classe hai automaticamente la possibilità di modificarla (non esiste compilazione, quindi non puoi fornire una DLL o simili).
Tuttavia, chiarisco subito, in C++/PHP e nei linguaggi che usano questa filosofia di OOP bisogna fare così, per rispettare la struttura del linguaggio.

Ma è proprio come filosofia che è errata; e ciò traspare anche da ciò che effettivamente avviene usando private in C++.
Quando scrivi una libreria, è giusto definire, si, i membri che non dovrebbero essere accessibili all'esterno, in modo da segnalare che non dovrebbero essere toccati a meno che non si sappia cosa si sta facendo.
Il programmatore C++ dice, usando private: "io sto facendo la classe, ha questi metodi privati, non li puoi toccare o ricevi errori a compile-time". Questo cosa significa? Che se ho bisogno di modificare o accedere ad un membro private, devo fare dei giochi di prestigio con i puntatori. Perché si, il private di C++ non è che una barriera a compile-time: a runtime non esistono modificatori d'accesso.

L'approccio giusto, che altri linguaggi usano da anni (vedi LISP, Python), è "io ti segnalo che questi metodi sono privati, non andrebbero toccati, a meno che tu non sappia che stai facendo: se lo fai e non funziona più niente, attaccati".

Tra l'altro, le definizioni di OOP dicono questo; dio solo sa cosa pensava Stroustrup quando ha rovinato C++ in quel modo.

Un esempio chiarificatore? Che succede se asder99 rende i membri private, e poi vuole scrivere una classe GuestBookAdmin che gli permette di amministrare il guestbook? Deve riscrivere il codice invece di appoggiarsi ai membr esistenti.i

Scusate per la lunga disgressione in merito, ma è un argomento che mi sta appassionando molto negli ultimi giorni. =)
 
sydarex ha detto:
CrAzY ha detto:
Non ho guardato attentamente il sorgente perché secondo me usare il db per un guestbook è uno spreco di query/banda...
Se vuoi un consiglio usa un file XML esterno per memorizzare il tutto (ovviamente col PHP mantieni i controlli sugli input).
Rispondo a te per tutti quelli che han detto che è uno spreco usare un database.
XML è più lento (devi leggere il file, parsarlo, e tenerlo in memoria), meno affidabile (o meglio, SimpleXML è sicuramente meno affidabile di MySQLi), e più difficile da usare rispetto ad un database. Non è uno spreco in nessun modo la vedi, anzi.
Tieni presente però che si tratta di un Guestbook, quindi il file non sarà mai abnorme come può diventare un database.
Inoltre se include alcune particolarità come il numero massimo di caratteri nei post e l'autocancellazione dei post più vecchi (esempio la Shoutbox del forum che si azzera ogni 24 ore), vedi che il file XML alla fine non è poi così tanto pesante.

Se poi alla fine lui dice che il database non gli serve quasi a niente, che è usato pochissimo, ed è sicuro che anche in futuro non gli servirà molto, allora può benissimo usare il db, specie se non ha molti utenti (bisogna anche vedere il livello di SPAM e flood).

Quindi ricapitoliamo i consigli venuti fuori da questo mio post:
- Limite al numero di caratteri nel post.
- Controllare il numero di post, rimuovendo quelli più vecchi/mostrando solo gli ultimi (utile l'idea di usare AJAX per visualizzare i post più vecchi).
- Aggiungere un'ulteriore controllo sui post per verificare la presenza di alcune parole indesiderate (insulti, ecc...).
 
CrAzY ha detto:
Tieni presente però che si tratta di un Guestbook, quindi il file non sarà mai abnorme come può diventare un database.
Eh? Rimane sempre la stessa mole di dati. Non c'entra nulla. E' il concetto stesso di accesso e parse di un file che è molto più pesante di una query.
CrAzY ha detto:
Inoltre se include alcune particolarità come il numero massimo di caratteri nei post e l'autocancellazione dei post più vecchi (esempio la Shoutbox del forum che si azzera ogni 24 ore), vedi che il file XML alla fine non è poi così tanto pesante.
Ci mancherebbe pure il farlo diventare di 50 megabyte :°°°D
CrAzY ha detto:
Se poi alla fine lui dice che il database non gli serve quasi a niente, che è usato pochissimo, ed è sicuro che anche in futuro non gli servirà molto, allora può benissimo usare il db, specie se non ha molti utenti (bisogna anche vedere il livello di SPAM e flood).
Mah, il senso di questa frase mi sfugge.

Fossero anche due (2) post, un file XML è più pesante del fare una stupida query su database da 1x10^-4 secondi.
 
si ma una query e tutto l'ambaradan che viene è un lavoraccio inutile per il server.. con un xml ci mette un'attimo a prender tutto o aggiungere... (poi un db costa di + per un hosting) poi ognuno sceglie come gli pare..
 
sydarex ha detto:
Il tuo post è esatto.. in parte.
Nel senso che è impeccabile se si adotta la visione dell'OOP portata in auge dal C++; questa visione però è, a mio modo di vedere, errata, e mi piacerebbe spiegare il perché.

E' il classico ragionamento inculcato da C++; e cioè "quando scrivi una classe, sei in guerra con chi la userà".
Ora, quando in C++ è un approccio che potrebbe durare a una discussione superficiale, in PHP perde completamentre significato.
Perché, a differenza di C++, in PHP usando una classe hai automaticamente la possibilità di modificarla (non esiste compilazione, quindi non puoi fornire una DLL o simili).
Tuttavia, chiarisco subito, in C++/PHP e nei linguaggi che usano questa filosofia di OOP bisogna fare così, per rispettare la struttura del linguaggio.
Mah... se hai bisogno di modificare la classe per utilizzarla correttamente vuol dire che la classe è pensata e progettata male. L'OOP è pensata per la massima riusabilità del codice, se devo mettere mano ad una classe per farla funzionare vuol dire che o è stata scritta male la classe o la cosa che sto facendo io è una cappellata. Non so... a te è mai servito modificare MySQLi??

Ma è proprio come filosofia che è errata; e ciò traspare anche da ciò che effettivamente avviene usando private in C++.
Quando scrivi una libreria, è giusto definire, si, i membri che non dovrebbero essere accessibili all'esterno, in modo da segnalare che non dovrebbero essere toccati a meno che non si sappia cosa si sta facendo.
Il programmatore C++ dice, usando private: "io sto facendo la classe, ha questi metodi privati, non li puoi toccare o ricevi errori a compile-time". Questo cosa significa? Che se ho bisogno di modificare o accedere ad un membro private, devo fare dei giochi di prestigio con i puntatori. Perché si, il private di C++ non è che una barriera a compile-time: a runtime non esistono modificatori d'accesso.
Mai sentito parlare di metodi get/set?

L'approccio giusto, che altri linguaggi usano da anni (vedi LISP, Python), è "io ti segnalo che questi metodi sono privati, non andrebbero toccati, a meno che tu non sappia che stai facendo: se lo fai e non funziona più niente, attaccati".

Tra l'altro, le definizioni di OOP dicono questo; dio solo sa cosa pensava Stroustrup quando ha rovinato C++ in quel modo.

Un esempio chiarificatore? Che succede se asder99 rende i membri private, e poi vuole scrivere una classe GuestBookAdmin che gli permette di amministrare il guestbook? Deve riscrivere il codice invece di appoggiarsi ai membr esistenti.i

Scusate per la lunga disgressione in merito, ma è un argomento che mi sta appassionando molto negli ultimi giorni. =)
Vale lo stesso discorso di prima. Se usi l'ereditarietà ed è stato fatto un buon lavoro di incapsulamento usi i metodi get/set per ovviare al problema (per quanto riguarda gli attributi). Poi esiste anche lo specificatore d'accesso protected. Ovvero, io mi metto nell'ottica che in futuro qualcuno voglia espandere la classe e voglio fornire metodi (o attribuiti) direttamente accessibili, dichiaro i metodi (o attribuiti) protected e la classe che li erediterà potrà usarli.
 
xmario ha detto:
si ma una query e tutto l'ambaradan che viene è un lavoraccio inutile per il server.. con un xml ci mette un'attimo a prender tutto o aggiungere... (poi un db costa di + per un hosting) poi ognuno sceglie come gli pare..
... ma perché persistete?
UNA QUERY impiega millesimi di secondo, e non è pesante proprio una ceppa perché il server MySQL runna COMUNQUE. Un file XML va LETTO dal filesystem (primo overhead), PARSATO (secondo overhead), TENUTO IN MEMORIA (terzo overhead), RISCRITTO se ci sono modifiche (quarto overhead).
Un file XML non gestisce in alcun modo la concorrenza.
Un file XML non è la via giusta perché XML non esiste per questi task.

Cioè, sono concetti BASILARI, scusate. ._.

stoner ha detto:
Mah... se hai bisogno di modificare la classe per utilizzarla correttamente vuol dire che la classe è pensata e progettata male. L'OOP è pensata per la massima riusabilità del codice, se devo mettere mano ad una classe per farla funzionare vuol dire che o è stata scritta male la classe o la cosa che sto facendo io è una cappellata. Non so... a te è mai servito modificare MySQLi??
Appunto, rendere un membro private limita il riutilizzo del codice, in quanto l'utilizzatore è limitato nell'utilizzo; private limita l'utilizzo della classe per i task per cui è stata pensata.
stoner ha detto:
Mai sentito parlare di metodi get/set.
Non ho capito. Se ciò che volevi scrivere è una domanda, allora:
- Tu se codi una classe e vuoi mantenere un attributo privato (intendo: per uso interno), realizzi le set/get?
- Ha senso utilizzare set/get invece che modificare direttamente i membri? A che pro, incapsulamento? Mi pare un ragionamento fallace, una cosa che si fa per abitudine, ma ti sarei grato se ti spiegassi meglio.
stoner ha detto:
Vale lo stesso discorso di prima. Se usi l'ereditarietà ed è stato fatto un buon lavoro di incapsulamento usi i metodi get/set per ovviare al problema (per quanto riguarda gli attributi). Poi esiste anche lo specificatore d'accesso protected. Ovvero, io mi metto nell'ottica che in futuro qualcuno voglia espandere la classe e voglio fornire metodi (o attribuiti) direttamente accessibili, dichiaro i metodi (o attribuiti) protected e la classe che li eredità potrà usarli.
Ma è proprio l'utilità dell'incapsulamento che critico, e che è FUORI dalla definizione teorica originaria della programmazione orintata agli oggetti.
Quanto a protected, ancora, non ne vedo l'utilità ancora più che di private, visto che mi basta fare una classe wrapper per aggirarla.
Non è meglio usare una convenzione per i metodi privati (come l'underscore iniziale, o ancora addirittura il name mangling se proprio si vuole), visto che:
- Private limita l'uso, il riuso e l'estendibilità della classe
- Protected è aggirabile
Quindi:
- Se questa filosofia di OOP è per ARRESTARE l'uso libero del codice, allora fallisce perché aggirabile;
- Se questa filosofia di OOP è per EVITARE GLI ERRORI PERMETTENDO L'USO LIBERO CONSAPEVOLE, allora fallisce perché va aggirata artificiosamente.
In entrambi i casi fallisce.
 
Ritornado allo script, ho effettuato dei controlli per ogni variabile non accettando alcun carattere eccetto lettere e numeri (questo per essere sicuro di non subire alcun tipo di attacco), ma sei io faccio una cosa del tipo:

Codice:
<?php
$t = htmlentities($_POST['t']);
$n = htmlentities($_POST['n']);
$ts = htmlentities($_POST['ts']);
$g = new Guestbook($t, $n, $ts);
?>

eseguendo queste query dello script:

Codice:
INSERT INTO guest(titolo, nick, testo) VALUES('$this->titolo','$this->nick','$this->testo');
SELECT * FROM guest ORDER BY id DESC;

senza utilizzare le regex, non potrei subire nessun tipo di attacco..giusto?
 
Stato
Discussione chiusa ad ulteriori risposte.