Go Back   CodingForums.com > :: Server side development > PHP > Post a PHP snippet

Before you post, read our: Rules & Posting Guidelines

Reply
 
Thread Tools Rate Thread
Enjoy an ad free experience by logging in. Not a member yet? Register.
Old 09-10-2012, 12:26 AM   PM User | #1
vroom
New Coder

 
Join Date: Sep 2012
Posts: 71
Thanks: 0
Thanked 8 Times in 8 Posts
vroom is an unknown quantity at this point
Asynchronous GET/POST Requests (PHP5)

The following PHP5 snippet defines an AsyncTCP class that will allow you to open and manage multiple requests to remote servers simultaneously.

While I obviously didn't invent the concept I have wrapped what I've seen within a class, added the ability to use either GET or POST, and created a very simple test script to show how it works (to follow).

PHP Code:
<?php

// ##########################################################################
// Name: AsyncTCP.php
// Date: 09-Sep-2012
// Prog: gvroom [at] gmail.com (http://hackedcpu.com/) 
//
// Desc: Provide asynchronous TCP/IP communication.  Script will continue to
//       run and allow retrieval of message (if desired) after some or all of
//       the base functionality has completed.
//
// Note: This is not expected to be used (advanced) in a tight loop. Caller
//       is expected to use sleep() or microsleep() to release CPU.
//
// Source: http://www.codingforums.com/showthread.php?t=272694
// ##########################################################################

class AsyncTCP
{
   
// Connection parameters
   // ---------------------
   
private $transport;
   private 
$host;
   private 
$port;
   private 
$uri;
   private 
$postdata;
   private 
$timeout;

   
// Connected socket details
   // ------------------------
   
private $s;
   private 
$status;
   private 
$error;
   private 
$written;
   private 
$data;

   
// ***********************************************************************
   // The timeout variable is used for connections only. Socket timeouts
   // are defined in the advance function.
   // ***********************************************************************
   
public function __construct($transport,$host,$port,$uri,$postdata='',$timeout=7)
   {
      
$this->transport $transport;   // tcp, ssl
      
$this->host      $host;        // domain.com, www.domain.com
      
$this->port      $port;        // 80, 8080, 443
      
$this->uri       $uri;         // /xmlapi.php /x.php?token=abc
      
$this->postdata  $postdata;    // properly encoded
      
$this->timeout   $timeout;     // 5, 20

      
$this->s         null;         // no connection yet
      
$this->status    'ready';      // no status yet
      
$this->error     0;            // no errors yet
      
$this->written   0;            // not written yet
      
$this->data      '';           // accumulated response
   
}

   
// ***********************************************************************
   // Simple status checks
   // ***********************************************************************
   
public function isReady()   { return ( $this->status == 'ready'); }
   public function 
isDone()    { return ( $this->status == 'done' || $this->error 0); }
   public function 
isWritten() { return ( $this->written ); }
   public function 
wasError()  { return ( $this->error ); }
   public function 
getStatus() { return ( $this->status ); }
   public function 
getData()   { return ( $this->data); }

   
// ***********************************************************************
   // Connect to the remote server.  Unfortunately, based on the time taken
   // to connect this appears not be an asynchronous event... though the read
   // and write management certainly is.
   // ***********************************************************************
   
public function connect()
   {
      
$errno   0;
      
$errstr  '';
      
$this->stream_socket_client($this->transport."://".$this->host.":".$this->port
                                     
,$errno
                                     
,$errstr
                                     
,$this->timeout
                                     
,STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);

      
$this->status 'connected';
      if ( 
$errno )
      {
         
$this->error $errno;
         
$this->status 'connect failed: $errrstr ($errno)';
      }

      return 
$this->error;
   }

   
// ***********************************************************************
   // Manage the connection. Basically, advance through a series of actions
   // to send a request and get the response.
   // ***********************************************************************
   
public function advance()
   {
      static 
$sockets = array();
      static 
$seconds 0;
      static 
$usec    100;
      static 
$readlen 8192;

      
$sockets['id']  = $this->s;
      
$read           $sockets;
      
$write          $sockets;
      
$except         null;

      
$n stream_select($read$write$except$seconds$usec);

      if ( 
$n )
      {
         
// Perform available read operations
         // ---------------------------------
         
foreach ($read as $r)
         {
            
$chunk fread($r$readlen);
            if ( 
$chunk === FALSE )
               
$this->status 'connect or read error';
            else
            {
               
$this->data  .= $chunk;
               
$this->status 'reading';
            }

            if ( 
strlen($chunk) < $readlen )
               
$this->status 'done';
         }

         
// Perform pending write operations
         // --------------------------------
         
foreach ($write as $w)
         {
            if ( !
$this->written )
            {
               
// Adjust for GET or POST requests
               // -------------------------------
               
$method 'GET';
               
$host   $this->host;
               
$port   $this->port;
               
$uri    $this->uri;
               
$headers "Host: $host\r\n";

               if ( 
strlen($this->postdata) )
               {
                  
$method 'POST';
                  
$length strlen($this->postdata);
                  
$headers .= "Content-type: application/x-www-form-urlencoded\r\n";
                  
$headers .= "Content-length: $length\r\n";
               }
               
$headers .= "\r\n";

               
// Build the message bundle
               // ------------------------
               
$msg  "$method $uri HTTP/1.0\r\n";
               
$msg .= $headers;
               
$msg .= $this->postdata;

               
fwrite($w,$msg);
               
$this->status  'sent; waiting for response';
               
$this->written 1;
            }
         }

      } 
// if ( n )

      
return $this->status;

   } 
// function advance()

// class AsyncTCP

Last edited by vroom; 09-10-2012 at 02:25 AM..
vroom is offline   Reply With Quote
Old 09-10-2012, 12:29 AM   PM User | #2
vroom
New Coder

 
Join Date: Sep 2012
Posts: 71
Thanks: 0
Thanked 8 Times in 8 Posts
vroom is an unknown quantity at this point
Here is the test script with sample output to follow...

PHP Code:
<?php

// ####################################
// ### TEST TCP AND SSL CONNECTIONS ###
// ####################################

$atime microtime(TRUE);

echo 
"initialize object data:<br>\n";
$elapsed sprintf("%0.7f",microtime(TRUE) - $atime);
echo 
"... elapsed: $elapsed<br>\n";
echo 
"<br>\n";

$c1 = new AsyncTCP('tcp','www.google.com','80','/');
$elapsed sprintf("%0.7f",microtime(TRUE) - $atime);
echo 
"c1 " $c1->getStatus() . "<br>\n... elapsed: $elapsed<br>\n";

$c2 = new AsyncTCP('ssl','gmail.google.com','443','/');
$elapsed sprintf("%0.7f",microtime(TRUE) - $atime);
echo 
"c2 " $c2->getStatus() . "<br>\n... elapsed: $elapsed<br>\n";

echo 
"<br>\n";
for ( ;; )
{
   if ( 
$c1->isReady() )
   {
      echo 
"... issueing c1 connect ";
      
$c1->connect();
      
$elapsed sprintf("%0.7f",microtime(TRUE) - $atime);
      echo 
"... c1 " $c1->getStatus() . " at elapsed $elapsed<br>\n<br>\n";
   }

   if ( 
$c2->isReady() )
   {
      echo 
"... issueing c2 connect ";
      
$c2->connect();
      
$elapsed sprintf("%0.7f",microtime(TRUE) - $atime);
      echo 
"... c2 " $c2->getStatus() . " at elapsed $elapsed<br>\n<br>\n";
   }

   if ( !
$c1->isDone() )
      
$c1->advance();
   if ( !
$c2->isDone() )
      
$c2->advance();

   
$elapsed sprintf("%0.7f",microtime(TRUE) - $atime);
   echo 
"elapsed: $elapsed<br>\n";
   echo 
"... c1: " $c1->getStatus() . "<br>\n";
   echo 
"... c2: " $c2->getStatus() . "<br>\n";

   if ( 
$c1->isDone() && $c2->isDone() )
      break;

   
usleep(5000);
}

echo 
"<br>\n";
echo 
"c1:<br>\n" htmlentities($c1->getData()) . "<br><br>\n";
echo 
"c2:<br>\n" htmlentities($c2->getData()) . "<br><br>\n";
vroom is offline   Reply With Quote
Old 09-10-2012, 12:34 AM   PM User | #3
vroom
New Coder

 
Join Date: Sep 2012
Posts: 71
Thanks: 0
Thanked 8 Times in 8 Posts
vroom is an unknown quantity at this point
This is a run against two Google servers (both GET requests one via SSL). Notice how both connections "advance" to different status values at different times. There may be a bug in the read logic as the first response may be cut off (I'll edit the original post if/when I find it).

Quote:
initialize object data:
... elapsed: 0.0000050

c1 ready
... elapsed: 0.0000379
c2 ready
... elapsed: 0.0000510

... issueing c1 connect ... c1 connected at elapsed 0.0026510

... issueing c2 connect ... c2 connected at elapsed 0.0182369

elapsed: 0.0183511
... c1: sent; waiting for response
... c2: sent; waiting for response
elapsed: 0.0234740
... c1: sent; waiting for response
... c2: sent; waiting for response
elapsed: 0.0285921
... c1: sent; waiting for response
... c2: sent; waiting for response
elapsed: 0.0337579
... c1: sent; waiting for response
... c2: done
elapsed: 0.0388761
... c1: sent; waiting for response
... c2: done
elapsed: 0.0440390
... c1: done
... c2: done

c1:
HTTP/1.0 200 OK Date: Sun, 09 Sep 2012 23:13:26 GMT Expires: -1 Cache-Control: private, max-age=0 Content-Type: text/html; charset=ISO-8859-1 Set-Cookie: PREF=ID=6772...snip...nhdt; expires=Tue, 09-Sep-2014 23:13:26 GMT; path=/; domain=.google.com Set-Cookie: NID=63=T6cC...snip...gZEw6; expires=Mon, 11-Mar-2013 23:13:26 GMT; path=/; domain=.google.com; HttpOnly P3P: CP="This is not a P3P policy! See http://www.google.com/support/accoun...&answer=151657 for more info." Server: gws X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN <!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head><meta content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for." name="description"><meta content="noodp" name="robots"><meta itemprop="image" content="/images/google_favicon_128.png"><title>Google</title><script>window.google={kEI:"liJNULy3OrK16AHIzYDQAw",getEI:function(a){var b;while(a&&!(a.getAttribute&&(b=a.getAttribute("eid"))))a=a.parentNode;return b||google.kEI},https:function(){return window.location.protocol=="https:"},kEXPI:"17259,23628,23670,30316,32690,35704,38034,39523,39976,400 0116,4000229,4000260,4000308,4000352,4000354,4000472,4000476,4000517,4000545,4000553,4000562,4000593 ,4000616,4000849",kCSI:{e:"17259,23628,23670,30316,32690,35704,38034,39523,39976,4000116,4000229,400 0260,4000308,4000352,4000354,4000472,4000476,4000517,4000545,4000553,4000562,4000593,4000616,4000849 ",ei:"liJNULy3OrK16AHIzYDQAw"},authuser:0, ml:function(){},kHL:"en",time:function(){return(new Date).getTime()},log:function(a,b,c,e){var d=new Image,h=google,i=h.lc,f=h.li,j="";d.onerror=(d.onload=(d.onabort=function(){delete i[f]}));i[f]=d;if(!c&&b.search("&ei=")==-1)j="&ei="+google.getEI(e);var g=c||"/gen_204?atyp=i&ct="+a+"&cad="+b+j+"&zx="+google.time(); var k=/^http:/i;if(k.test(g)&&google.https()){google.ml(new Error("GLMM"),false,{src:g});delete i[f];return}d.src=g;h.li=f+1},lc:[],li:0,Toolbelt:{},y:{},x:function(a,b){google.y[a.id]=[a,b];return false}};window.google.sn="webhp";window.google.timers={};window.google.startTick=function(a,b){windo w.google.timers[a]={t:{startnew Date).getTime()},bfr:!(!b)}};window.google.tick=function(a,b,c){if(!window.google.timers[a])google.startTick(a);window.google.timers[a].t[b]=c||(new Date).getTime()};google.startTick("load",true);try{}catch(u){} var _gjwl=location;function _gjuc(){var e=_gjwl.href.indexOf("#");if(e>=0){var a=_gjwl.href.substring(e);if(a.indexOf("&q=")>0||a.indexOf("#q=")>=0){a=a.substring(1);if(a.indexOf( "#")==-1){for(var c=0;c<a.length{var d=c;if(a.charAt(d)=="&")++d;var b=a.indexOf("&",d);if(b==-1)b=a.length;var f=a.substring(d,b);if(f.indexOf("fp=")==0){a=a.substring(0,c)+a.substring(b,a.length);b=c}else if(f=="cad=h")return 0;c=b}_gjwl.href="/search?"+a+"&cad=h";return 1}}}return 0}function _gjp(){!(window._gjwl.hash&& window._gjuc())&&setTimeout(_gjp,500)}; window._gjp&&_gjp();</script><style>#gb{font:13px/27px Arial,sans-serif;height:30px}#gbz,#gbg{position:absolute;white-space:nowrap;top:0;height:30px;z-index:1000}#gbz{left:0;padding-left:4px}#gbg{right:0;padding-right:5px}#gbs{background:transparent;position:absolute;top:-999px;visibility:hidden;z-index:998}.gbto #gbs{background:#fff}#gbx3,#gbx4{background-color:#2d2d2d;background-image:none;_background-image:none;background-position:0 -138px;background-repeat:repeat-x;border-bottom:1px solid #000;font-size:24px;height:29px;_height:30px;opacity:1;filter:alpha(opacity=100);position:absolute;top:0;width :100%;z-index:990}#gbx3{left:0}#gbx4{right:0}#gbb{position:relative}#gbbw{right:0;left:0;position:absolute;t op:30px;width:100%}.gbtcb{position:absolute;visibility:hidden}#gbz .gbtcb{right:0}#gbg .gbtcb{left:0}.gbxx{display:none !important}.gbxo{opacity:0 !important;filter:alpha(opacity=0) !important}.gbm{position:absolute;z-index:999;top:-999px;visibility:hidden;text-align:left;border:1px solid #bebebe;background:#fff;-moz-box-shadow:-1px 1px 1px rgba(0,0,0,.2)

c2:
HTTP/1.0 200 OK Cache-Control: private, max-age=604800 Expires: Sun, 09 Sep 2012 23:13:26 GMT Date: Sun, 09 Sep 2012 23:13:26 GMT Refresh: 0;URL=https://gmail.google.com/mail/ Content-Type: text/html; charset=ISO-8859-1 X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Content-Length: 236 Server: GSE <html><head><meta http-equiv="Refresh" content="0;URL=https://gmail.google.com/mail/" /></head><body><script type="text/javascript" language="javascript"><!-- location.replace("https://gmail.google.com/mail/") --></script></body></html>

Last edited by vroom; 09-11-2012 at 02:51 PM.. Reason: Note differences between connection requests.
vroom is offline   Reply With Quote
Old 09-10-2012, 12:36 AM   PM User | #4
vroom
New Coder

 
Join Date: Sep 2012
Posts: 71
Thanks: 0
Thanked 8 Times in 8 Posts
vroom is an unknown quantity at this point
Finally, a shorter test against my own server (POST) and google (SSL)...

Quote:
initialize object data:
... elapsed: 0.0000050

c1 ready
... elapsed: 0.0000410
c2 ready
... elapsed: 0.0000570

... issueing c1 connect ... c1 connected at elapsed 0.0012650

... issueing c2 connect ... c2 connected at elapsed 0.0163491

elapsed: 0.0165250
... c1: sent; waiting for response
... c2: sent; waiting for response
elapsed: 0.0229831
... c1: sent; waiting for response
... c2: sent; waiting for response
elapsed: 0.0282569
... c1: done
... c2: sent; waiting for response
elapsed: 0.0334899
... c1: done
... c2: done

c1:
HTTP/1.1 200 OK Server: nginx/1.1.19 Date: Sun, 09 Sep 2012 23:01:45 GMT Content-Type: text/html; charset=utf-8 Connection: close X-Powered-By: PHP/5.3.10-1ubuntu3.2 Set-Cookie: PHPSESSID=fag2vg36ormvo5eopd86lmu3r6; expires=Sun, 16-Sep-2012 23:01:45 GMT; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache <br> <b>H A C K E D C P U &nbsp; D E M O</b><br> <br> Enter a small amount of English language text (up to 512 bytes):<br> <form method="post" action=""> <textarea name="textin" rows="9" cols="100">this is my input text.</textarea><br> <input type="submit" name="submit" value="Go"><br> </form> Processing...<br> <br> this: 1<br> is: 1<br> my: 1<br> input: 2<br> text: 1<br> <br> 5 tokens found containing 5 unique words<br> <br> <hr> PHP processing took 0.00458884 seconds<br>

c2:
HTTP/1.0 200 OK Cache-Control: private, max-age=604800 Expires: Sun, 09 Sep 2012 23:01:48 GMT Date: Sun, 09 Sep 2012 23:01:48 GMT Refresh: 0;URL=https://gmail.google.com/mail/ Content-Type: text/html; charset=ISO-8859-1 X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Content-Length: 236 Server: GSE <html><head><meta http-equiv="Refresh" content="0;URL=https://gmail.google.com/mail/" /></head><body><script type="text/javascript" language="javascript"><!-- location.replace("https://gmail.google.com/mail/") --></script></body></html>
vroom is offline   Reply With Quote
Reply

Bookmarks

Tags
async, php5, post, tcpip

Jump To Top of Thread


Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 09:32 AM.


Advertisement
Log in to turn off these ads.