codice:
<?php
/*
* +----------+
* | TODO |
* +----------+
* - Completare l'elenco delle funzioni e scriverle
* - Implementare il sistema per gestire le callbacks
*
* +----------+
* | NOTE |
* +----------+
* - Tutto deve essere gestito dalla routine doevents (connessione, lettura dati, scrittura dati e altro ancora)
*
* +--------------+
* | FUNZIONI |
* +--------------+
* - [OK] clsSocket
* - [OK] connect
* - [OK] close
* - [OK] bind
* - [OK] __set_error
* - [OK] __log
* - [!!] doEvents
* - [NO] write
* - [NO] read
* - [NO] listen
* - [NO] set_callback
* - [NO] get_strerror
* - [NO] __manage_callbacks
*/
// Stati classe pubblici
define('S_SOCKET_CLOSED' , "\x00");
define('S_SOCKET_CONNECTING' , "\x01");
define('S_SOCKET_CONNECTED' , "\x02");
define('S_SOCKET_WRITING' , "\x03");
define('S_SOCKET_LISTING' , "\x04");
class clsSocket {
/*
* Public Vars
*/
var $local_host = ""; // Indirizzo Locale
var $local_port = 0; // Porta locale
var $remote_host = ""; // Indirizzo Remoto
var $remote_port = 0; // Porta remota
var $state = S_SOCKET_CLOSED; // Stato della connessione
/*
* Private Vars
*/
var $__conn_starttime = 0; // Avvio tentativo di connessione
var $__conn_timeout = 0; // Timeout di connessione
var $__oSocket = 0; // Oggetto della socket
var $__error_code = 0; // Codice d'errore interno
// Costruttore della classe
function clsSocket() {
// Controlla se l'estensione specifica per le socket è stata caricata
if (!extension_loaded('sockets')) {
// Carica i settaggi dal file ini
$php_ini = ini_get_all();
// rileva se il safe mode è attivo o il DL è stato disabilitato da php.ini
if (
(
isset($php_ini['enable_dl']['local_value']) == FALSE ||
$php_ini['enable_dl']['local_value'] == ''
) || (
isset($php_ini['safe_mode']['local_value']) == TRUE &&
$php_ini['safe_mode']['local_value'] == 1
)
) {
$this->__log('FATAL', 'SAFE MODE attivo o DL disabilitato! Impossibile caricare a run-time il modulo Sockets!', TRUE, TRUE);
}
// Crea il prefisso
$prefix = (PHP_SHLIB_SUFFIX == 'dll') ? 'php_' : '';
// Prova a caricare l'estensione
if (!@dl($prefix . 'sockets.' . PHP_SHLIB_SUFFIX)) {
$this->__log('FATAL', 'Caricamento del modulo Sockets fallito!', TRUE, TRUE);
} else {
$this->__log('NOTICE', 'Modulo Sockets caricato correttamente');
}
}
// Crea la socket
$this->__oSocket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Controlla se la creazione è correttamente riuscita
if (!is_resource($this->__oSocket)) {
$this->__log('FATAL', 'Creazione della socket fallita! - Errore: ' . socket_strerror(socket_last_error()), TRUE, TRUE);
}
// Imposta la socket in modalità non blocking
$res = @socket_set_nonblock($this->__oSocket);
// Controlla se l'operazione è riuscita
if (!$res) {
$this->__log('FATAL', 'Impossibile impostare la socket in modalità non blocking! - Errore: ' . socket_strerror(socket_last_error($this->__oSocket)), TRUE, TRUE);
}
// Imposta la reusabilità della socket
$res = @socket_set_option($this->__oSocket, SOL_SOCKET, SO_REUSEADDR, 1);
// Controlla se l'operazione è riuscita
if (!$res) {
$this->__log('FATAL', 'Impossibile impostare la socket in modalità riusabile! - Errore: ' . socket_strerror(socket_last_error($this->__oSocket)), TRUE, TRUE);
}
}
// Questa funzione si occupa di gestire gli eventi
function doEvents() {
// Controlla lo stato della socket
switch($this->state) {
case S_SOCKET_CLOSED: // Non fa nulla
break;
case S_SOCKET_CONNECTING: // Gestisce la connessessione ad un host
// Dichiara alcune vars
$tmpINT_ConnStatus = 0;
// Controlla se la connessione è riuscita correttamente
$tmpARRAY_write = array($this->__oSocket);
$tmpARRAY_error = array($this->__oSocket);
$tmpINT_SocketNum = @socket_select($r=array(), $tmpARRAY_write, $tmpARRAY_error, 0, 10);
// Controlla che il socket_select è riuscito
if ($tmpINT_SocketNum === FALSE) {
// Se è fallito il select
$tmpINT_ConnStatus = 4;
}
// Verifica se socket_select ha restituito un valore maggiore di zero
// se si procede a controllare se la connessione è riuscita o se si
// sono verificati errori
if ($tmpINT_ConnStatus === 0 AND $tmpINT_SocketNum > 0) {
if (count($tmpARRAY_write)) { // Tutto è andato a buon fine
$tmpINT_ConnStatus = 1;
} else { // Si è verificato un'errore
$tmpINT_ConnStatus = 2;
}
}
// Nessun valore è stato ritornato di conseguenza controlla se il
// timeout per la connessione è stato superato
if ($tmpINT_ConnStatus == 0) {
// Esegue il controllo
if ((time() - $this->__conn_starttime) > $this->__conn_timeout) {
$tmpINT_ConnStatus = 3;
}
}
switch($tmpINT_ConnStatus) {
case 1: // Connessione Riuscita
// Recupera i parametri di connessione dell'host remoto
socket_getpeername($this->__oSocket, $tmpSTR_addr, $tmpINT_port);
// Imposta il nuovo stato
$this->state = S_SOCKET_CONNECTED;
// Richiama la callback
$this->__manage_callbacks('connection_done', array($tmpSTR_addr,$tmpINT_port));
echo "CONNESSIONE ESEGUITA!!!";
break;
case 2: // Connessione Fallita
// Imposta l'errore
// Imposta il nuovo stato
// Richiama la callback
echo "connessione fallita";
break;
case 3: // Timeout di connessione
// Imposta l'errore
// Imposta il nuovo stato
// Richiama la callback
echo "timeout di connessione";
break;
case 4: // socket_select fallita
// Imposta l'errore
// Imposta il nuovo stato
// Richiama la callback
echo "socket_select fallita";
break;
}
break;
case S_SOCKET_CONNECTED: // Controlla che la socket sia aperta,
// che non vi siano errori ed infine
// controlla se ci sono dati da leggere
break;
case S_SOCKET_LISTING: // Essendo la socket in modalità
// listing resta in attesa e controlla
// quando vi sono socket da accettare
break;
}
}
// Imposta lo stato di connessione
function connect($remote_host, $remote_port, $timeout = 60) {
// Avvia il tentativo di connessione
@socket_connect($this->__oSocket, $remote_host, $remote_port);
// Imposta lo stato su CONNESSIONE IN CORSO
$this->state = S_SOCKET_CONNECTING;
// Imposta la data di inizio connessione
$this->__conn_starttime = time();
// Imposta il timeout di connessione
$this->__conn_timeout = $timeout;
}
// Chiude la connessione ed imposta lo stato di chiusura della socket
function close() {
// Chiude la socket
@socket_close($this->__oSocket);
// Imposta lo stato
$this->state = S_SOCKET_CLOSED;
}
// Imposta la porta e l'host locale
function bind($local_host, $local_port = 0) {
// Binda la socket sull'indirizzo e la porta passate
if ($local_port === 0) {
// La porta non è stata passata e quindi non viene impostata
$res = @socket_bind($this->__oSocket, $local_host);
} else {
// La posta è stata passata tra i parametri e quindi viene impostata
$res = @socket_bind($this->__oSocket, $local_host, $local_port);
}
// Controlla se l'operazione è riuscita correttamente
if ($res === FALSE) {
// Stampa a video l'errore
$this->__log('WARNING', 'Impossibile bindare la socket su ' . $local_host . (($local_port !== 0) ? ":{$local_port}" : '') . '! Errore: ' . socket_strerror(socket_last_error($this->__oSocket)), TRUE, TRUE);
}
}
// Scrive nella socket
function write() {}
// Legge dalla socket
function read() {}
// Imposta la socket in modalità listen
function listen() {}
// Imposta le callbacks
function set_callback($callback_name, $callback_function) {}
// Legge la stringa d'errore
function get_strerror($error_code) {}
/*
* PRIVATE FUNCTIONS
*/
// Funzione per impostare l'errore
function __set_error($error_code) {
$this->__error_code = $error_code;
}
// Funzione per stampare a video un LOG
function __log($level, $msg, $timestamp=TRUE, $die=FALSE) {
// Controlla se deve aggiungere o meno il timestamp
if ($timestamp === TRUE) {
// Log con timestamp
$tmpmsg = "[{$level}] [" . date('d/m/Y H:n:i') . "] {$msg}\n";
} else {
// Log senza timestamp
$tmpmsg = "[{$level}] {$msg}\n";
}
// Stampa a video il timestamp
echo $tmpmsg;
// Controlla se è richiesta l'uscita
if ($die === TRUE) {
// Se si esce
exit;
}
}
// Funzione per gestire le callbacks
function __manage_callbacks($callback_name, $params = array(), $return_result = FALSE) {
}
}
?>
serve per gestire in maniera TOTALMENTE asincrona, usando delle callbacks o eventi, le socket