Questo articolo si propone di mostrare come si può iniziare a utilizzare Nodo per aggiungere funzionalità in tempo reale per il vostro sito web basato su PHP. In primo luogo, vedremo un po ‘ di più a ciò che rende Nodo una buona misura per le applicazioni in tempo reale, prima di andare a dimostrare come costruire un news feed in tempo reale e incorporarlo nel tuo sito web PHP.
Basato su thread vs basato su eventi
Tradizionalmente PHP è servito con Apache e il modulo mod_php. Se esegui il comando ” top ” sul tuo server Web basato su Unix, probabilmente vedrai un gran numero di processi Apache che servono i client Web. In questa configurazione, ogni richiesta client genera in genere un nuovo processo Apache fino a quando tutta la RAM disponibile non viene esaurita. Recentemente, nginx e php-fpm sono emersi come il metodo più efficiente per servire i siti Web PHP, ma anche in questa configurazione ogni client è servito da un diverso processo PHP. Il punto chiave qui è che, dall’inizio alla fine, una richiesta client sta utilizzando un processo PHP per l’intera durata. Se l’elaborazione di ogni richiesta richiede molto tempo, le risorse del server possono essere utilizzate molto rapidamente.
Nel nodo, un singolo processo Nodo serve in genere ogni client in un ciclo di eventi. Per processi costosi e di lunga durata come l’accesso al file system, a un database o a un’API remota, si raccomanda di utilizzare chiamate di metodo asincrone invece di bloccarle. Ciò è ottenuto attraverso l’uso di callback che vengono attivati quando un’azione come l’accesso al file system è terminata. Ciò significa che un singolo processo Nodo può continuare a elaborare nuove richieste mentre l’operazione costosa viene eseguita in background. Quando l’operazione costosa è completa, torna nella coda del ciclo degli eventi per essere elaborata ulteriormente dal Nodo.
In sostanza, Node può essere visto come un ambiente simile per la creazione di applicazioni come Twisted di Python o EventMachine in Ruby. Node ha anche un server HTTP pronto per la produzione integrato, quindi non ha bisogno di un server separato per eseguirlo come Apache o Nginx, migliorando ulteriormente i suoi requisiti di risorse snelle (escludendo eventuali perdite di memoria).
var http = require('http');http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn');}).listen(1337, '127.0.0.1');console.log('Server running at http://127.0.0.1:1337/');
L’esempio di codice sopra mostra come è possibile scrivere un server web “hello world” obbligatorio in poche righe di codice. La prima riga mostra l’utilizzo del sistema di moduli noto come CommonJS che il nodo utilizza per includere moduli separati. La funzione require è integrata e in questo caso importa il modulo HTTP del nodo per l’uso nell’applicazione. La seconda riga crea un nuovo oggetto server Web. Si noti che il primo parametro del metodo createServer è una funzione anonima. La maggior parte dei metodi in Node accetta una funzione di callback come parametro e questa è la chiave per creare applicazioni basate su eventi.
La riga successiva di esecuzione è la riga 5, che utilizza il concatenamento del metodo per chiamare il metodo listen sul valore restituito dal metodo createServer (il valore restituito è l’istanza del modulo HTTP). Il metodo listen fa sì che il server inizi ad accettare richieste HTTP sulla porta 1337 su localhost. L’ultima riga scrive un messaggio alla console per dire che il server è stato avviato. Solo quando viene effettuata una richiesta al server viene chiamata la funzione anonima, che imposta il codice di stato HTTP su 200 OK e imposta l’intestazione Content-Type. Il messaggio’ Hello World ‘ viene finalmente scritto nel corpo della risposta HTTP sulla riga 4.
Perché dovrei usare il nodo.js Allora?
Il modello event-driven di Node è particolarmente adatto per applicazioni in tempo reale come giochi, feed di notizie e applicazioni di chat. Inoltre, consente anche di utilizzare la stessa lingua sul frontend e sul backend. JavaScript sta diventando sempre più popolare in quanto vengono create applicazioni lato client più ricche e i browser Web diventano più veloci nell’esecuzione di JavaScript. Dover passare da una lingua all’altra può essere frustrante.
WordPress Spezial
Alles rund um WordPress im Entwickler Spezial Vol. 10-ab 18.11.2016 im Handel.
WordPress ist längst weit mehr als ein simples Blogsystem. In diesem Sonderheft beschäftigen sich zahlreiche Spezialisten mit allen wichtigen Fragen rund um das verbreitetste CMS im Web; und dabei geht es nicht nur um klassische Themen, sondern auch um di Marketing di Affiliazione, E-Commerce u.v.m.
in Secondo luogo, ha un buon supporto per i WebSockets. Mentre è possibile supportare WebSockets in PHP, la natura asincrona del nodo e il suo server HTTP integrato lo rendono più adatto. I WebSocket sono un modo per mantenere una connessione persistente al browser al fine di inviare rapidamente i dati al client. Rispetto alle soluzioni precedenti come il polling lungo o la cometa, i WebSocket comportano una latenza molto più bassa, in quanto non vi è alcun sovraccarico di istanziare una connessione HTTP ogni volta che alcuni dati devono essere inviati. Lo svantaggio di WebSockets è che si tratta di una funzione HTML5, e come tale non è così ben supportato nei browser come semplice vecchio Ajax è. Tuttavia, è possibile ricorrere con grazia a tecniche alternative come il polling lungo nei browser che non supportano i WebSocket.
Alla Conferenza internazionale PHP di quest’anno puoi saperne di più sull’integrazione dei Nodi.js con PHP!
La Conferenza internazionale PHP è la prima conferenza PHP al mondo ed è stata un punto di riferimento per l’esperienza pragmatica di alto livello in PHP e tecnologie web per più di un decennio . All’IPC, esperti di fama internazionale del settore PHP si incontrano con utenti PHP e sviluppatori di grandi e piccole aziende. Scopri i nostri prezzi Early Bird per grandi sconti!
Ecco alcune sessioni di highlight da IPC:
- Rendere il tuo angolare.js Applicazione accessibile
Dirk Ginader (Google) - Dattiloscritto Decisionale JavaScript per lo Sviluppo di Più Produttivi e Robusto
Rainer Stropek (architetti software gmbh) - Come ottenere pronto per PHP 7
Sebastian Bergmann (thePHP.cc)
tenete a mente, però, il Nodo è un immaturo piattaforma rispetto a PHP. Originariamente creato nel 2009, è ancora nella sua infanzia e non ha ancora raggiunto la versione 1.0 – se questo è importante per voi. Potresti scoprire che le API che usi cambiano in futuro, o non essere in grado di trovare un framework che abbia lo stesso set di funzionalità del tuo framework PHP preferito. In effetti, nella mia esperienza, le librerie e i framework di terze parti disponibili tendono a consistere in bundle di funzionalità molto più piccoli che è necessario mettere insieme.
C’è anche un rischio maggiore di perdite di memoria che portano l’applicazione a una brusca frenata. I processi Node in genere vengono eseguiti continuamente, mentre i processi PHP tendono ad essere respawned periodicamente per negare l’effetto delle perdite di memoria.
La parte integrante
Il news feed sarà integrato con un sito web PHP di base che gestisce gli accessi e le sessioni degli utenti, utilizzando una configurazione comune di php-fpm e nginx. Useremo JavaScript per comunicare con un’applicazione Nodo sul lato server e aggiornare dinamicamente il news feed senza ricaricare la pagina. Prima però, un rapido da parte sulle sessioni.
Se non lo stai già facendo, dovresti utilizzare un’area di archiviazione centralizzata per le tue sessioni (Figura 1). Memcached può essere facilmente utilizzato per questa attività utilizzando il gestore di salvataggio della sessione integrato nell’estensione PECL memcached. Se vuoi la possibilità di riavviare il server memorizzando le tue sessioni senza perdere dati, Redis è una buona scommessa. In entrambi i casi, uno storage di sessione centralizzato consente di caricare l’applicazione su più server Web. Consente inoltre di condividere i dati della sessione con applicazioni create con altri linguaggi di programmazione.
Figura 1: Architettura di sessione condivisa.
Tuttavia, c’è un piccolo problema di analisi dei dati di sessione. Di seguito viene mostrato il formato di serializzazione predefinito di una sessione PHP:
not|a:2:{i:0;s:4:"easy";i:1;a:1:{s:2:"to";s:5:"parse";}}
Potrebbe sembrare possibile utilizzare la manipolazione delle stringhe per analizzarlo, ma potrebbero esserci casi limite difficili da risolvere. Sarebbe bello se la sessione fosse serializzata nel tanto amato formato JSON:
{"this":{"is": "easier", "to": "parse"}}
Molto meglio. È abbastanza facile scrivere il proprio serializzatore di sessione che convertirà tutto ciò che memorizzi in format _SESSION in formato JSON, vedi la mia versione.
In alternativa, si potrebbe prendere in considerazione msgpack che può essere configurato per serializzare le sessioni, come nel codice seguente, che dimostra anche come utilizzare memcached come gestore di salvataggio della sessione.
È disponibile una libreria di terze parti per Node che può serializzare e deserializzare msgpack, disponibile in npm (Node Package Manager, contiene un gran numero di moduli che possono essere utilizzati nell’applicazione con una semplice installazione di npm ). Vedremo ora di costruire il news feed usando il Nodo e incorporandolo in un’applicazione PHP.
PHP App
L’applicazione PHP gestisce semplicemente gli accessi utente e le sessioni. Le sessioni sono memorizzate in memcached, ma potrebbero essere facilmente memorizzate in redis. Il codice seguente mostra i frammenti di una sola pagina dell’applicazione (per il codice sorgente completo di andare a github.com/lboynton/phphants-march-php).
// // <!]>
La prima riga dello script include il Compositore autoloader file, il che significa che tutte le dipendenze sono caricate automaticamente, eliminando la necessità di separare include o require linee (nota del Redattore: per ulteriori informazioni su Compositore, vedere Jefersson Nathan de O. Articolo di Chaves). In questo caso, il gestore di salvataggio della sessione è l’unico pezzo di codice esterno richiesto. Tuttavia, è molto facile includere eventuali pacchetti di terze parti disponibili su packagist o altrove in un secondo momento utilizzando Composer che verrà anche aggiunto automaticamente al caricamento automatico. Le righe 3 e 4 impostano una connessione a memcached, mentre il gestore di salvataggio della sessione viene inizializzato e registrato con PHP nelle righe 5-14. Gli utenti sono loggati semplicemente specificando il nome utente come parametro GET, anche se in un sistema reale questo dovrebbe essere sostituito con un sistema di autenticazione più funzionale.
Sul lato JavaScript, utilizziamo alcune librerie di terze parti: jQuery, underscore.js e il Socket.IO client, che è la parte del browser del modulo Nodo che utilizzeremo per inviare i dati al browser. L’io.connect method call crea una connessione all’applicazione Node, che potrebbe utilizzare uno dei numerosi trasporti come websockets o Ajax a seconda del supporto del browser. Presa.il metodo on imposta un gestore di eventi che renderà una notizia sulla pagina ogni volta che un evento “news” viene attivato dal lato server.
Nota: L’applicazione utilizza Composer per l’installazione del gestore di salvataggio della sessione e Bower, un gestore di pacchetti per l’installazione di risorse lato client. Per installare Bower, eseguire ‘npm-g install bower’. Quindi per installare le risorse, fare ‘bower install’. In alternativa, aggiornare i tag di script e i fogli di stile con le versioni locali.
L’applicazione viene servita utilizzando nginx. Ecco il file di configurazione di nginx:
upstream node { server localhost:3000;}server { listen 8080; server_name php-node-demo.localhost; root /home/lee/public_html/php-node-demo; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ .php$ { include fastcgi_params; fastcgi_index index.php; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location ~ /socket.io { proxy_pass http://node; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }}
Le righe 1-3 definiscono un server upstream che esegue l’app Node. Qualsiasi richiesta che finisce in .php verrà inviato a php-fpm (linee 15-20), mentre tutte le richieste con /socket.io nell’URL verrà passato all’app Node (linee 22-27). Le linee 25 e 26 dicono a nginx di supportare la commutazione del protocollo e abilitare websockets per essere proxy al Nodo. Ciò significa che l’app PHP e l’app Node sono entrambe eseguite sulla stessa porta, per quanto riguarda il client.
Nodo.js App
Il Nodo.js app gestisce semplicemente tutte le richieste dei clienti per il news feed. Frammenti di esso sono visualizzati di seguito (vedi github.com/lboynton/phphants-march-node per la fonte completa).
io.set('authorization', function(handshake, callback) { var cookies = cookie.parse(handshake.headers.cookie); mcClient.get('sessions/' + cookies.PHPSESSID, function(error, result) { if (error) { callback(error, false); } else if (result) { handshake.session = JSON.parse(result); callback(null, true); } else { callback('Could not find session ID ' + cookies.PHPSESSID + ' in memcached', false); } });});io.sockets.on('connection', function(socket) { var session = socket.handshake.session; sockets = socket;);function getNews() { redis.blpop('news', 0, function(err, data) {news = JSON.parse(data);if (typeof news.to !== 'undefined') { if (typeof sockets !== 'undefined') {sockets.emit('news', news.content); }} else { io.sockets.emit('news', news.content);}process.nextTick(getNews); });}
Presa.io è una libreria che fornisce una singola API per eseguire la comunicazione WebSocket tra client e server. Supporta anche il fallback grazioso quando WebSocket non sono disponibili nel browser, e altre caratteristiche utili in un protocollo di messaggistica come battiti cardiaci, timeout e il supporto di disconnessione che non è supportato fuori dalla scatola con l’API HTML5 WebSocket.
Il primo snippetconfigura l’autorizzazione per le richieste che Socket.io riceve. Quando arriva una nuova richiesta, analizzerà i cookie nella richiesta e tenterà di recuperare una chiave memcached che corrisponde al valore del cookie PHPSESSID (il nome predefinito per il cookie di sessione PHP). Se trovato, memorizzerà il valore analizzato della chiave memcached nei dati.sessione a cui è possibile accedere in seguito.
Il prossimo snippet configura cosa dovrebbe accadere quando Socket.io attiva l’evento ‘connessione’. Questo evento viene attivato durante la connessione iniziale dal client, una volta autorizzato. I dati di sessione precedentemente recuperati da memcached possono ora essere referenziati tramite il socket.variabile stretta di mano. Quando il client si connette, l’istanza socket viene associata al nome utente del client in modo che i messaggi possano essere inviati a singoli utenti.
L’ultimo frammento contiene una funzione per verificare la presenza di nuove notizie in una coda redis. Usa il comando BLPOP in redis, il che significa che se la coda è vuota, si bloccherà fino a quando alcuni dati non verranno aggiunti alla coda prima di spuntarla. Quando alcuni dati possono essere estratti dalla coda, vengono analizzati come JSON prima di determinare se il contenuto deve essere inviato a tutti i client connessi o solo a un singolo utente. Il contenuto della notizia viene inviato al socket corretto chiamando il metodo emit () sul socket che è stato associato all’utente in precedenza nel gestore eventi di connessione.
Infine, il processo del nodo.Il metodo nextTick () viene chiamato con la funzione getNews come argomento. Ciò significa che la funzione getNews verrà chiamata la prossima volta che viene eseguito il ciclo di eventi e continuerà a controllare la coda redis per i dati fino a quando l’applicazione non viene arrestata.
Per installare, utilizzare npm per scaricare le dipendenze richieste. Quindi eseguire l’applicazione con node app.js.
Si dovrebbe ora essere in grado di aprire un browser web e passare ahttp://localhost:8080/?username=bob e vedere l’applicazione news feed. Ora apri una seconda scheda o finestra del browser con un nome utente diverso, ad esempiohttp://localhost:8080/?username=sally.
Aggiornamento del feed
L’aggiornamento del feed è semplicemente un caso di spingere una nuova notizia nella coda. Connettersi all’interfaccia redis CLI utilizzando il comando redis-cli. Questa è una shell interattiva per redis, che consente di inviare comandi al server direttamente. L’esempio di codice qui sotto mostra come spingere alla coda:
rpush news '{"content": "Testy test", "to": "bob"}'
Nella finestra del browser Web che hai aperto per l’utente bob dovresti vedere la voce di notizie scorrere verso il basso dalla parte superiore della pagina. In alternativa, è possibile inviare notizie sia a bob, sally che a qualsiasi altro client connesso escludendo il parametro “a”, come segue:
rpush news '{"content": "Everyone should see this"}'
In un’applicazione reale si spingono i dati nella coda da PHP, usando ad esempio l’estensione php-redis o predis.
Conclusione
Questo è solo un semplice esempio per dimostrare come Node può essere integrato con la tua applicazione PHP. Ci sono alcune limitazioni nell’implementazione. Ad esempio, ricorderà solo una connessione da ciascun utente. Pertanto, se un utente ha più schede o finestre aperte al news feed, verrà aggiornata solo una pagina. Questo può essere risolto memorizzando un array di socket per utente e tenendo traccia di ogni connessione e disconnessione per aggiungere o rimuovere i socket dall’array. È lasciato al lettore implementare una soluzione migliore. Ha anche mostrato strumenti come Composer e Bower che ti consiglio vivamente di utilizzare nelle tue applicazioni.
Lee Boynton è uno sviluppatore con sede in Hampshire, Regno Unito, con un particolare interesse per le applicazioni in tempo reale come la messaggistica istantanea e flussi di attività. Ha conoscenza dello sviluppo e dell’amministrazione lato server e dello sviluppo frontend. Lavora presso la società locale Symbios Group ed è anche membro di PHP Hampshire per chi aiuta a organizzare eventi.