2015-06-28 17 views
21

Desidero trasferire i dati dal server al browser. Sono già a conoscenza della funzione php ob_flush() che invia il buffer di output. Ho bisogno di aiuto con un po 'di logica. Sto usando l'API in tempo reale di Facebook, quindi voglio trasmettere i dati all'utente ogni volta che Facebook visita il mio sito web.Invio di dati al browser utente dal server

Ecco il mio codice che sto cercando di inviare dati al browser ma non funziona.

+0

Hai guardato in WebSockets? Qualcosa come http://socketo.me/ potrebbe essere sufficiente. In generale, però, eseguire una richiesta su un intervallo dal client di solito fa il trucco. – som

+0

Volevo utilizzare la libreria di socket php ufficiale http://php.net/manual/en/book.sockets.php ma come implementarlo con il browser –

+0

Penso che quello che stai cercando sia un tutorial su websockets in PHP . Perché non cercarlo e poi fare domande in base ai risultati? – som

risposta

8

Come suggerito da @som, è possibile utilizzare semplicemente le richieste con un intervallo tra di esse, non è necessario utilizzare le prese.

Ma il fatto è che si sta tentando di ricevere dati dall'API e trasmetterli direttamente al browser, tutto in una volta. È meglio se separi questi due passaggi.

nello script che riceve i dati da Facebook, negozio che i dati in un database o da qualche altra parte:

if($_SERVER['REQUEST_METHOD'] == "POST"){ 
    $updates = json_decode(file_get_contents("php://input"), true); 

    insertDataToDatabase($updates); // you'll have to implement this. 
} 

Poi impostare una pagina di monitoraggio:

monitor.php

<script> 
lastId = 0; 

$(document).ready(function() { 
    getNewDataAtInterval(); 
}); 

function getNewDataAtInterval() { 
    $.ajax({ 
     dataType: "json", 
     url: "getData.php", 
     data: {lastId: lastId} 
    }).done(function(data) { 
     for(i=0; i<data.messages.length; i++) { 
      $("#messages").append("<p>" + data.messages[i]['id'] + ": " + data.messages[i]['message'] + "</p>"); 
      if (data.messages[i]['id'] > lastId) lastId = data.messages[i]['id']; 
     } 

     setTimeout(getNewDataAtInterval, 10000); 
    }).fail(function(jqXHR, textStatus) { 
     alert("Request failed: " + jqXHR.responseText); 
    }); 
} 
</script> 

<div id="messages"></div> 

Infine, creare uno script sul lato server per restituire un JSON con i nuovi messaggi caricati dal database.

getData.php

$lastId = $_GET['lastId']; 
$newMessages = getUpdatesFromDatabase($lastId); 

exit(json_encode(array("messages"=>$newMessages))); 

function getUpdatesFromDatabase($lastId) { 
    // I'm using this array just as an example, so you can see it working. 
    $myData = array(
     array("id"=>1,"message"=>"Hi"), 
     array("id"=>2,"message"=>"Hello"), 
     array("id"=>3,"message"=>"How are you?"), 
     array("id"=>4,"message"=>"I'm fine, thanks") 
    ); 

    $newMessages = array(); 
    foreach($myData as $item) { 
     if ($item["id"] > $lastId) { 
      $newMessages[] = $item; 
      $newLastId = $item["id"]; 
     } 
    } 

    return $newMessages; 
} 
+0

Non voglio memorizzare alcun dato. –

+0

Puoi avere qualche tipo di archiviazione? Ti piace un file temporaneo? In questo caso, 'insertDataToDatabase' dovrebbe scrivere su un file di testo nel tuo server. Ogni volta che qualcuno accede a 'monitor.php', la funzione' getUpdatesFromDatabase' lo leggerà, invierà il contenuto al client ed eliminerà il file. –

+0

Ho accesso alla memoria sia del database che del file temporaneo. Ma non voglio usarlo ... Perché qualche volta i dati di Facebook sono in ritardo fino a un minuto e la memorizzazione e il recupero dei dati aumenteranno il tempo di elaborazione. Voglio spingere i dati all'istante. –

1

Con il protocollo HTTP convenzionali, i browser web richiedere sempre il server per la risposta. Una volta inviata la risposta, il server chiude la connessione.

La vera tecnologia di connessione persistente come WebSocket è una delle eccezioni in cui un browser effettua un tipo specifico di connessione al server e, avendo la comprensione dell'intenzione, il server manterrebbe la connessione aperta. In questo modo, non appena i dati vengono "spinti" nel browser, la connessione è sempre pronta. Utilizzando questo approccio, non è necessario salvare temporaneamente i dati poiché si dovrebbe semplicemente "passarlo".

Le tecniche di polling (compreso il polling lungo, in cui il server continua a inviare "heartbeat" al client come se una risposta non significativa sta lentamente scorrendo) possono essere utilizzate come work-around, ma c'è sempre un intervallo di tempo in cui la connessione non è più aperta finché non si verifica il ciclo successivo. Quando la connessione è assente, l'unica opzione è di salvare temporaneamente i dati in modo che quando il browser ritorna, è possibile inviare i dati in sospeso. Nel caso si stia pensando di archiviarlo in una variabile temporanea, tenere presente che con lo script PHP una volta completata l'esecuzione, tutti i dati allocati nella memoria associata in tale ambito sono sottoposti a garbage collection.

1

Perché la necessità di spingere? Forse mi manca un indizio qui, ma altrimenti è l'unico modo per risolvere questo problema? Vuoi essere in grado di impostare il testo di diciamo un div che chiamiamo statusUpdate che mostra i nuovi stati da facebook quando vengono pubblicati?Quindi è possibile:

Suddividere il processo in un thread di raccolta dello stato eseguito come un daemon che tenta continuamente di recuperare dall'API FB (non conosco alcuna specifica o non ha alcuna conoscenza dell'AP FB ma posso solo immagina che ci siano chiamate a cercare se ci sono nuovi stati).

Non importa se l'API è in streaming o che è necessario connettersi ogni X secondo come possiamo prendere in considerazione? Vorrei installare un daemon in php con e quindi eseguirlo con SSH con il comando: nohup php daemon.php per iniziare uno script con un loop senza fine in questo modo:

Define('SLEEP', 1); // loop every second 

while (true) { 

    // do your thing, dont exit 

    if($fbMonkey->checkNewStatus()){ 
     $fbMonkey->toDatabase(new_statuses); 
    } 

    if(some_reason_to_exit() == TRUE){ 
     exit; 
    } 

    sleep(SLEEP); 
} 
// While ends with break 

Allora forse comprendono in HTML di utente di destinazione (fine del browser del processo) una funzione JavaScript che legge dalla tabella con gli stati riempiti dal daemon e quindi quelli che non sono stati contrassegnati come visualizzati (dagli utenti o qualcosa di simile) e restituiscono gli stati non letti al browser . Se creiamo un ciclo infinito nel browser per esso e permettiamo di aggiornare lo stato div UpdateUpdate e con i nuovi contenuti (html o tekst non importa?). Vorrei lasciare che una chiamata come questa indugiasse e controllare ogni 20 secondi circa e aggiornare il div.

http://www.w3schools.com/ajax/tryit.asp?filename=tryajax_xml2

function loadXMLDoc(url) 
{ 
var xmlhttp; 
var txt,xx,x,i; 
if (window.XMLHttpRequest) 
  {// code for IE7+, Firefox, Chrome, Opera, Safari 
  xmlhttp=new XMLHttpRequest(); 
  } 
else 
  {// code for IE6, IE5 
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
  } 
xmlhttp.onreadystatechange=function() 
  { 
  if (xmlhttp.readyState==4 && xmlhttp.status==200) 
    { 
    txt="<table border='1'><tr><th>Title</th><th>Artist</th></tr>"; 
    x=xmlhttp.responseXML.documentElement.getElementsByTagName("CD"); 
    for (i=0;i<x.length;i++) 
      { 
      txt=txt + "<tr>"; 
      xx=x[i].getElementsByTagName("TITLE"); 
        { 
        try 
          { 
          txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; 
          } 
        catch (er) 
          { 
          txt=txt + "<td>&nbsp;</td>"; 
          } 
        } 
    xx=x[i].getElementsByTagName("ARTIST"); 
      { 
        try 
          { 
          txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; 
          } 
        catch (er) 
          { 
          txt=txt + "<td>&nbsp;</td>"; 
          } 
        } 
      txt=txt + "</tr>"; 
      } 
    txt=txt + "</table>"; 
    document.getElementById('txtCDInfo').innerHTML=txt; 
    } 
  } 
xmlhttp.open("GET",url,true); 
xmlhttp.send(); 
} 

O sono completamente del marchio qui?

2

Ho trovato Pusher e Redis per i dati push dal server al browser mentre cercavo la soluzione migliore.

Pusher

Si può comodamente consumare eventi trasmessi utilizzando il driver Pusher usando di Pusher JavaScript SDK.

this.pusher = new Pusher('pusher-key'); 

this.pusherChannel = this.pusher.subscribe('reference_id'); 

this.pusherChannel.bind('SomeEvent', function(message) { 
    console.log(message.user); 
}); 

Redis

Se si utilizza l'emittente Redis, è necessario scrivere il proprio Redis pub/sub consumatore di ricevere i messaggi e trasmettere utilizzando la tecnologia websocket di la tua scelta. Ad esempio, puoi scegliere di utilizzare la famosa libreria Socket.io scritta nel nodo.

Utilizzando la socket.io e ioredis librerie nodo, è possibile scrivere rapidamente un broadcaster evento di pubblicare tutti gli eventi che vengono trasmessi dalla vostra applicazione:

var app = require('http').createServer(handler); 
var io = require('socket.io')(app); 

var Redis = require('ioredis'); 
var redis = new Redis(); 

app.listen(6001, function() { 
    console.log('Server is running!'); 
}); 

function handler(req, res) { 
    res.writeHead(200); 
    res.end(''); 
} 

io.on('connection', function(socket) { 
    // 
}); 

redis.psubscribe('*', function(err, count) { 
    // 
}); 

redis.on('pmessage', function(method, channel, message) { 
    message = JSON.parse(message); 
    io.emit(channel + ':' + message.event, message.data); 
}); 
0

bella discussione.Me piace: D @andy: grande, per me la prima volta che qualcuno potrebbe spiegare la differenza vera accurata e io a farlo: D @Marcos Dimitrio Concordo

Io ho eseguito un pool di thread maledettamente brutto di Twitter Demoni API che fanno esattamente quello tranne la cosa push $ _POST da facebook se ho capito bene. Controlla i tweet in tempo reale per gli array di centinaia/migliaia di cluster di parole chiave tramite lo streamin api Firehose. Questa è la strada da percorrere o subire una sconfitta terribile altrimenti: D IMHO, naturalmente. Questa è la metà di due demoni chiamati getTweets e parseTweets.

<?php 
ob_start(); 
require_once('config/phirehose-config.php'); 
require_once('lib.php'); 
$oDB = new db; 

// run as a daemon aka background process 
while (true) { 

    // Process all statuses 
    $query = 'SELECT cache_id, raw_tweet ' . 
    'FROM json_cache'; 
    $result = $oDB->select($query); 
    while($row = mysqli_fetch_assoc($result)) { 

    $cache_id = $row['cache_id']; 
// $status = unserialize(base64_decode($row['raw_tweet'])); 
    $tweet_object = json_decode($row['raw_tweet'],false); 


    // JSON payload for statuses stored in the database 
    // serialized base64 raw data 

     // Delete cached copy of tweet 
     // $oDB->select("DELETE FROM json_cache WHERE cache_id = $cache_id"); 

     // Limit tweets to a single language, 
     // such as 'en' for English 
     //if ($tweet_object->lang <> 'nl') {continue;} 

    // Test status update before inserting 
    $tweet_id = $tweet_object->id_str; 

    if ($oDB->in_table('tweets','tweet_id=' . $tweet_id)) {continue;} 

    $tweet_text = $oDB->escape($tweet_object->text);  
    $created_at = $oDB->date($tweet_object->created_at); 
    if (isset($tweet_object->geo)) { 
     $geo_lat = $tweet_object->geo->coordinates[0]; 
     $geo_long = $tweet_object->geo->coordinates[1]; 
    } else { 
     $geo_lat = $geo_long = 0; 
    } 
    $user_object = $tweet_object->user; 
    $user_id = $user_object->id_str; 
    $screen_name = $oDB->escape($user_object->screen_name); 
    $name = $oDB->escape($user_object->name); 
    $profile_image_url = $user_object->profile_image_url; 


    // Add a new user row or update an existing one 
    $field_values = 'screen_name = "' . $screen_name . '", ' . 
     'profile_image_url = "' . $profile_image_url . '", ' . 
     'user_id = ' . $user_id . ', ' . 
     'name = "' . $name . '", ' . 
     'location = "' . $oDB->escape($user_object->location) . '", ' . 
     'url = "' . $user_object->url . '", ' . 
     'description = "' . $oDB->escape($user_object->description) . '", ' . 
     'created_at = "' . $oDB->date($user_object->created_at) . '", ' . 
     'followers_count = ' . $user_object->followers_count . ', ' . 
     'friends_count = ' . $user_object->friends_count . ', ' . 
     'statuses_count = ' . $user_object->statuses_count . ', ' . 
     'time_zone = "' . $user_object->time_zone . '", ' . 
     'last_update = "' . $oDB->date($tweet_object->created_at) . '"' ;  

    if ($oDB->in_table('users','user_id="' . $user_id . '"')) { 
     $oDB->update('users',$field_values,'user_id = "' .$user_id . '"'); 
    } else {    
     $oDB->insert('users',$field_values); 
    } 

    // percist status to database 

    $field_values = 'tweet_id = ' . $tweet_id . ', ' .... 


    //... Somethings are to be for da cook alone, its hard work   

      foreach ($entities->hashtags as $hashtag) { 

     $where = 'tweet_id=' . $tweet_id . ' ' . 
     'AND tag="' . $hashtag->text . '"';  

     if(! $oDB->in_table('tweet_tags',$where)) { 

     $field_values = 'tweet_id=' . $tweet_id . ', ' . 
      'tag="' . $hashtag->text . '"'; 

     $oDB->insert('tweet_tags',$field_values); 
     } 
    } 
    foreach ($entities->urls as $url) { 

     if (empty($url->expanded_url)) { 
     $url = $url->url; 
     } else { 
     $url = $url->expanded_url; 
     } 

     $where = 'tweet_id=' . $tweet_id . ' ' . 
     'AND url="' . $url . '"';  

     if(! $oDB->in_table('tweet_urls',$where)) { 
     $field_values = 'tweet_id=' . $tweet_id . ', ' . 
      'url="' . $url . '"'; 

     $oDB->insert('tweet_urls',$field_values); 
     } 
    }  
    } 

    if(DEBUG){ 
    echo ob_get_contents(); 
    ob_clean(); 
    }else{ 
    ob_clean(); 
    } 

    // Longer sleep equals lower server load 
    sleep(1); 
} 
?> 

Ideale anche per ragni e crawler per i quali avere il mio personale. Dimostrami un modo migliore per farlo, tutto considerato come le risorse e la scalabilità come un widget di sito Web connesso in modo permanente per gli aggiornamenti di stato FB è davvero come utilizzare Echelon come un televisore remoto di nuovo imho).

0

Se hai solo bisogno di una soluzione semplice e non sei preoccupato per la compatibilità con i browser più vecchi e hai una situazione di traffico basso, il server-sent events potrebbe fare il trucco.

È possibile creare un'istanza con una riga se lo script di generazione del messaggio push si trova sullo stesso server.

var evtSource = new EventSource("messages.php"); 

Quindi una funzione per gestire i messaggi in arrivo.

evtSource.onmessage = function(e) { 

     console.log(e.data); 
    } 

messages.php deve avere intestazione impostato come

header("Content-Type: text/event-stream\n\n"); 

Poi fanno un ciclo infinito impostato un intervallo come desiderato.

esempio:

header("Content-Type: text/event-stream\n\n"); 
date_default_timezone_set("Pacific/Auckland"); // as required 
$sleepTime = 8; // # of seconds delayed between notifications 

while (1) 
{ 

    // Send a message at $sleepTime second intervals. 
    echo 'data: The time is ' . date("H:i:s") . "\n\n"; 

    ob_end_flush(); 
    flush(); 
    sleep($sleepTime); 
} 

Ovviamente avresti bisogno di leggere i messaggi da qualche parte e presente, come richiesto, ma almeno questo esempio ti dà un'idea di come creare un flusso di eventi, senza la necessità di entrare in la relativa complessità di WebSocket.

Disclaimer: Non sono un esperto con PHP, ma questa soluzione sembra funzionare per me . Se c'è qualche problema con questo, sarei desideroso di sentire.

0

Invia una richiesta solo quando si recuperano i dati dal server. E al server dormi finché non trovi che c'è qualcosa di nuovo da inviare e rispedire la risposta.

Continuare quanto sopra fino a quando la tua pagina è attiva e vedrai che i dati vengono inviati. Ciò evita di eseguire il ping del server a intervalli regolari.

Non sono sicuro se ci si riferisce in questa sede, https://en.wikipedia.org/wiki/Comet_(programming)

Problemi correlati