Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 4 of 4
  1. #1
    New Coder
    Join Date
    Sep 2012
    Posts
    71
    Thanks
    0
    Thanked 8 Times in 8 Posts

    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.

  • #2
    New Coder
    Join Date
    Sep 2012
    Posts
    71
    Thanks
    0
    Thanked 8 Times in 8 Posts
    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";

  • #3
    New Coder
    Join Date
    Sep 2012
    Posts
    71
    Thanks
    0
    Thanked 8 Times in 8 Posts
    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).

    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.

  • #4
    New Coder
    Join Date
    Sep 2012
    Posts
    71
    Thanks
    0
    Thanked 8 Times in 8 Posts
    Finally, a shorter test against my own server (POST) and google (SSL)...

    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>


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •