domenica 13 maggio 2012
Sessioni PHP: cosa sono, come si usano
Pubblicato su HTML.it un mio articolo con qualche trucco non banale per una corretta configurazione delle sessioni in PHP
Sessioni PHP: cosa sono, come si usano
martedì 27 marzo 2012
Distribuzione delle sessioni su più server in load balancing
La distribuzione delle sessioni è un problema che riguarda la scalabilità dei siti web su più server, in particolare per PHP che di norma salva le sessioni su file system del singolo server.
In queste slides vedremo alcune strategie di risoluzione del problema (load balancing mirato, accentramento delle sessioni) e ci soffermeremo su una personale soluzione che prevede la distribuzione delle sessioni su più macchine contemporaneamente creando un’architettura a maglia attraverso l’uso di memcache.
lunedì 10 agosto 2009
La persistenza degli webservices
Quando si implementa un server Soap occorre fare attenzione al fatto che per ogni metodo invocato dal client il nostro script server verrà sempre riavviato (e la classe verrà re-istanziata)
Quindi se il nostro server è
< ?
class Doppio {
private $doppio;
public function set($numero){
$this->doppio=$numero;
}
public function get() {
return $this->doppio*2;
}
}
$server = new SoapServer( 'doppio.wsdl' );
$server->setClass('Doppio');
$server->handle();
?>
Ed il client è
< ?
$a = new SoapClient("http://127.0.0.1/Adv/xml/doppio.wsdl");
$a->set(5);
echo $a->get();
?>
Restituirà 0 perché ogni istruzione sarà vista come un lancio di script, per ovviare a questo inconveniente inserire nel server l’istruzione setPersistence
Così:
< ?
class Doppio {
private $doppio;
function __construct() {
$this->doppio=$_SESSION['doppio'];
}
function __sleep() {
$_SESSION['doppio']=$this->doppio;
}
. . . . codice precedente . . . .
}
session_start();
$server = new SoapServer( 'doppio.wsdl' );
$server->setClass('Doppio');
$server->handle();
?>
< ?
. . . . codice precedente . . . .
$server = new SoapServer( 'doppio.wsdl' );
$server->setClass('Doppio');
$server->setPersistence(SOAP_PERSISTENCE_SESSION);
$server->handle();
?>
Ma attenzione perché questa è una persistenza basata su sessioni quindi lo script viene sempre eseguito due volte ma tra l’una è l’altra l’oggetto viene salvato nella sessione
Quindi se il nostro server è
< ?
class Doppio {
private $doppio;
public function set($numero){
$this->doppio=$numero;
}
public function get() {
return $this->doppio*2;
}
}
$server = new SoapServer( 'doppio.wsdl' );
$server->setClass('Doppio');
$server->handle();
?>
Ed il client è
< ?
$a = new SoapClient("http://127.0.0.1/Adv/xml/doppio.wsdl");
$a->set(5);
echo $a->get();
?>
Restituirà 0 perché ogni istruzione sarà vista come un lancio di script, per ovviare a questo inconveniente inserire nel server l’istruzione setPersistence
Così:
< ?
class Doppio {
private $doppio;
function __construct() {
$this->doppio=$_SESSION['doppio'];
}
function __sleep() {
$_SESSION['doppio']=$this->doppio;
}
. . . . codice precedente . . . .
}
session_start();
$server = new SoapServer( 'doppio.wsdl' );
$server->setClass('Doppio');
$server->handle();
?>
< ?
. . . . codice precedente . . . .
$server = new SoapServer( 'doppio.wsdl' );
$server->setClass('Doppio');
$server->setPersistence(SOAP_PERSISTENCE_SESSION);
$server->handle();
?>
Ma attenzione perché questa è una persistenza basata su sessioni quindi lo script viene sempre eseguito due volte ma tra l’una è l’altra l’oggetto viene salvato nella sessione
Etichette:
php soap webservices persistenza
lunedì 27 luglio 2009
Webservices più veloci
Per velocizzare web services che restituiscono grosse quantità di dati (che si amplificano per l’effetto dell’XML in cui sono “imbustati”) può essere utile usare la compressione gzip nelle risposte del server
Es.
Client
< ?
$a = new SoapClient('myservice.wsdl',
array('compression' => SOAP_COMPRESSION_ACCEPT SOAP_COMPRESSION_GZIP)
); //abilitiamo la compressione GZIP per le risposte
..resto dello script
?>
Server
< ?
.. inclusione classi ...
$server = new SoapServer( 'myservice.wsdl' );
$server->setClass('myservice');
if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip')===false)
$server->handle();
else {
ob_start();
$server->handle();
$x=gzencode(ob_get_clean(), 7); //7 è più che sufficiente per non perdere tempo in compressione
header("Content-Encoding: gzip");
header("Content-Length: ".strlen($x));
echo $x;
}
/* in alternativa si potrebbe catturare con ob_start tutto l’output sempre salvo comprimerlo se il client lo supporta ma anche se la dimensione supera i 1024 bytes ad esempio */
?>
Es.
Client
< ?
$a = new SoapClient('myservice.wsdl',
array('compression' => SOAP_COMPRESSION_ACCEPT SOAP_COMPRESSION_GZIP)
); //abilitiamo la compressione GZIP per le risposte
..resto dello script
?>
Server
< ?
.. inclusione classi ...
$server = new SoapServer( 'myservice.wsdl' );
$server->setClass('myservice');
if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip')===false)
$server->handle();
else {
ob_start();
$server->handle();
$x=gzencode(ob_get_clean(), 7); //7 è più che sufficiente per non perdere tempo in compressione
header("Content-Encoding: gzip");
header("Content-Length: ".strlen($x));
echo $x;
}
/* in alternativa si potrebbe catturare con ob_start tutto l’output sempre salvo comprimerlo se il client lo supporta ma anche se la dimensione supera i 1024 bytes ad esempio */
?>
Etichette:
webservices php soap
venerdì 15 maggio 2009
Aguzza la vista
Perché questo script:
<?php
session_start();
?>
restituisce
Warning:: session_start() Cannot send session cookie - headers already sent by (output started at ...:1) ?
La sessione è basata sull’invio di un cookie, per l’appunto cookie di sessione, com’è noto i cookie si inviano nell’header dell’http quindi non si può inviare quel cookie attraverso il session_start() se prima si è fatta una echo.. ma non è stata fatta nessuna echo... ed invece si.
Si può notare (con molta attenzione ;-)) che prima dell’apertura del <?php è presente un'interlinea, che sia uno o un’infinità di caratteri quello è comunque un invio di testo che comporta la chiusura dell’header e l’impossibilità di inviare successivamente il cookie di sessione.
Sembra una sciocchezza ma non è raro che si perda tempo per un carattere sfuggito, magari all’inizio di uno script incluso.
<?php
session_start();
?>
restituisce
Warning:: session_start() Cannot send session cookie - headers already sent by (output started at ...:1) ?
La sessione è basata sull’invio di un cookie, per l’appunto cookie di sessione, com’è noto i cookie si inviano nell’header dell’http quindi non si può inviare quel cookie attraverso il session_start() se prima si è fatta una echo.. ma non è stata fatta nessuna echo... ed invece si.
Si può notare (con molta attenzione ;-)) che prima dell’apertura del <?php è presente un'interlinea, che sia uno o un’infinità di caratteri quello è comunque un invio di testo che comporta la chiusura dell’header e l’impossibilità di inviare successivamente il cookie di sessione.
Sembra una sciocchezza ma non è raro che si perda tempo per un carattere sfuggito, magari all’inizio di uno script incluso.
lunedì 11 maggio 2009
IP e MAC address del server
Ecco un trucco per recuperare il/i macaddress e relativo ip del server usando un’istanza COM (ovviamente su Windows)
<?
$wmi = new COM("WinMgmts:{impersonationLevel=impersonate}");
$IPConfigSet = $wmi->ExecQuery("SELECT Description,MACAddress,IPAddress
FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True");
$out=array();
foreach ($IPConfigSet as $i=>$IPConfig )
foreach($IPConfig->IPAddress as $ip)
if ($ip!='0.0.0.0')
echo $ip,' | ',$IPConfig->MACAddress,' | ',$IPConfig->Description,"\n";
?>
Ed il risultato sarà della forma
172.20.10.58 | 00:11:2F:B9:12:1D | Intel(R) PRO/100 VE Network Connection - Miniport dell'Utilità di pianificazione pacchetti
<?
$wmi = new COM("WinMgmts:{impersonationLevel=impersonate}");
$IPConfigSet = $wmi->ExecQuery("SELECT Description,MACAddress,IPAddress
FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True");
$out=array();
foreach ($IPConfigSet as $i=>$IPConfig )
foreach($IPConfig->IPAddress as $ip)
if ($ip!='0.0.0.0')
echo $ip,' | ',$IPConfig->MACAddress,' | ',$IPConfig->Description,"\n";
?>
Ed il risultato sarà della forma
172.20.10.58 | 00:11:2F:B9:12:1D | Intel(R) PRO/100 VE Network Connection - Miniport dell'Utilità di pianificazione pacchetti
Etichette:
com,
mac address,
PHP,
windows
venerdì 17 aprile 2009
Usare i Prepared Statements con le librerie Mysql
Com’è noto i prepared statement non sono supportati da mysql, (vedi anche io mio post "Mysql contro Mysqli" del 14/4/2009) ma sfruttando le istruzioni PREPARE ed EXECUTE del SQL di mysql ecco una funzioncina in grado di usarli; inoltre questi prepared statements possono essere riutilizzati da altri script che agganciano la stessa connessione persistente in quanto associati ad un nome calcolato in base alla query.
Naturalmente in questi statementes non c' binding con variabili del PHP ma sono utili per query particolarmente complicate o (meglio ancora) di aggiornamento del DB.
Naturalmente in questi statementes non c' binding con variabili del PHP ma sono utili per query particolarmente complicate o (meglio ancora) di aggiornamento del DB.
function mysql_query_prepared($sql, $parametri=false){
if (!is_array($parametri)) return mysql_query($sql); //uso standard
else {
$sql= str_replace(array("\r","\n","\t"),array('','',''), trim($sql)); //pulisce sql
$stmt_name="PS".md5($sql); //calcola un nome per il prepared statement
if (count($parametri)>0)
{//$parametri non vuoto, trasmette i parametri al server come variabili
foreach ($parametri as $k=>&$v) $vars["@A$k"]="@A$k:='".mysql_escape_string($v)."'";
mysql_query("set ".implode(",",$vars));
$usa_variabili=' using '.implode(',',array_keys($vars));
}
//Prova ad eseguire lo statemend direttamente
$query_stmt="execute $stmt_name $usa_variabili";
$esito=mysql_query($query_stmt);
if (mysql_errno()==1243)
{
//se non esiste uno statamente $stmt_name prova a crearlo e se ci riesce lo usa
if (mysql_query($x="prepare $stmt_name from '".mysql_escape_string($sql)."'"))
$esito=mysql_query($query_stmt);
else {//se non riesce a crearlo effettua una sostituzione manuale dei parametri
if ($parametri)
foreach (explode('?',$sql) as $i=>$parte)
$newSql.="$parte ".($parametri[$i]?"'".mysql_escape_string($parametri[$i])."'":'');
$esito=mysql_query($newSql); //e lo esegue normalmente
}
}
return $esito;
}
}
//Possibili usi
mysql_query_prepared("select * from persone where id=?", array(120)); //usa un PS parametrizzato
mysql_query_prepared("select * from persone where id=120", array()); //usa un PS non parametrizzato
mysql_query_prepared("select * from persone where id=120"); //utilizzo classico
Etichette:
mysql,
PHP,
prepared statements
Iscriviti a:
Post (Atom)
