• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • Examples
  • File List

system/classes/socketrequestprocessor.php

00001 <?php
00002 
00003 namespace Habari;
00004 
00005 class SocketRequestProcessor extends RequestProcessor
00006 {
00007 
00008   public function __construct()
00009   {
00010 
00011     // see if we can follow Location: headers
00012     if( ini_get('safe_mode') || ini_get('open_basedir') ) {
00013       $this->can_followlocation = false;
00014     }
00015 
00016     if( !defined('FILE_CACHE_LOCATION') ) {
00017       define('FILE_CACHE_LOCATION', HABARI_PATH . '/user/cache/');
00018     }
00019 
00020   }
00021 
00022   public function execute($method, $url, $headers, $body, $config)
00023   {
00024 
00025     // before we handle headers, see if we should add our compression headers
00026     if( $this->can_zlib() ) {
00027       $headers['Accept-Encoding'] = 'gzip,deflate';
00028     }
00029 
00030     $merged_headers = array();
00031     foreach ($headers as $k => $v) {
00032       $merged_headers[] = $k . ': ' . $v;
00033     }
00034 
00035     // parse out the URL so we can refer to individual pieces
00036     $url_pieces = InputFilter::parse_url($url);
00037 
00038     // set up the options we'll use when creating the request's context
00039     $options = array(
00040       'http' => array(
00041         'method' => $method,
00042         'header' => implode("\n", $merged_headers),
00043         'timeout' => $config['timeout'],
00044         'follow_location' => $this->can_followlocation, // 5.3.4+, should be ignored by others
00045         'max_redirects' => $config['max_redirects'],
00046 
00047         // and now for our ssl-specific portions, which will be ignored for non-HTTPS requests
00048         'verify_peer' => $config['ssl']['verify_peer'],
00049         //'verify_host' => $config['ssl']['verify_host'], // there doesn't appear to be an equiv of this for sockets - the host is matched by default and you can't just turn that off, only substitute other hostnames
00050         'cafile' => $config['ssl']['cafile'],
00051         'capath' => $config['ssl']['capath'],
00052         'local_cert' => $config['ssl']['local_cert'],
00053         'passphrase' => $config['ssl']['passphrase'],
00054       ),
00055     );
00056 
00057     if( $method == 'POST' ) {
00058       $options['http']['content'] = $body;
00059     }
00060 
00061 
00062     if( $config['proxy']['server'] != '' && !in_array($url_pieces['host'], $config['proxy']['exceptions']) ) {
00063       $proxy = $config['proxy']['server'] . ':' . $config['proxy']['port'];
00064 
00065       if( $config['proxy']['username'] != '' ) {
00066         $proxy = $config['proxy']['username'] . ':' . $config['proxy']['password'] . '@' . $proxy;
00067       }
00068 
00069       $options['http']['proxy'] = 'tcp://' . $proxy;
00070     }
00071 
00072     // create the context
00073     $context = stream_context_create($options);
00074 
00075     // perform the actual request - we use fopen so stream_get_meta_data works
00076     $fh = @fopen($url, 'r', false, $context);
00077 
00078     if( $fh === false ) {
00079       throw new \Exception(_t('Unable to connect to %s', array($url_pieces['host'])));
00080     }
00081 
00082     // read in all the contents -- this is the same as file_get_contens, only for a specific stream handle
00083     $body = stream_get_contents($fh);
00084 
00085     // get meta data
00086     $meta = stream_get_meta_data($fh);
00087 
00088     // close the connection before we do anything else
00089     fclose($fh);
00090 
00091     // did we timeout?
00092     if( $meta['timed_out'] == true ) {
00093       throw new RemoteRequest_Timeout(_t('Request timed out'));
00094     }
00095 
00096 
00097     // $meta['wrapper_data'] should be a list of the headers, the same as is loaded into $http_response_header
00098     $headers = array();
00099     foreach ($http_response_header as $header) {
00100 
00101       // break the header up into field and value
00102       $pieces = explode(': ', $header, 2);
00103 
00104       if( count($pieces) > 1 ) {
00105         // if the header was a key: value format, store it keyed in the array
00106         $headers[$pieces[0]] = $pieces[1];
00107       } else {
00108         // some headers (like the HTTP version in use) aren't keyed, so just store it keyed as itself
00109         $headers[$pieces[0]] = $pieces[0];
00110       }
00111 
00112     }
00113 
00114     // check to see if the response was compressed
00115     if( isset($headers['Content-Encoding']) ) {
00116       $encoding = trim($headers['Content-Encoding']);
00117 
00118       if( $encoding == 'gzip' ) {
00119         $body = $this->gzdecode($body);
00120       } else {
00121         if( $encoding == 'deflate' ) {
00122           $body = gzinflate($body);
00123         }
00124       }
00125     }
00126 
00127     $this->response_headers = $headers;
00128     $this->response_body = $body;
00129     $this->executed = true;
00130 
00131     return true;
00132 
00133   }
00134 
00135   private function can_zlib()
00136   {
00137 
00138     // make sure that the zlib extension is loaded
00139     if( !extension_loaded('zlib') ) {
00140       return false;
00141     }
00142 
00143     // since we have to write to a temp file to de-gzip, make sure we can do that
00144     $tmp = tempnam(FILE_CACHE_LOCATION, 'RRS'); // RRS for RemoteRequestSocket, get it?
00145 
00146     // if creating the temp file failed, that's it
00147     if( !$tmp ) {
00148       return false;
00149     }
00150 
00151     $fh = @fopen($tmp, 'w+b');
00152 
00153     // if actually opening the file for writing failed
00154     if( !$fh ) {
00155       return false;
00156     }
00157 
00158     fclose($fh);
00159 
00160     // now we should be good to go, let's clean up after ourselves
00161     if( file_exists($tmp) ) {
00162       unlink($tmp);
00163     }
00164 
00165     // and we're good
00166     return true;
00167 
00168   }
00169 
00170   private function gzdecode($body)
00171   {
00172 
00173     // create the temp file to write to
00174     $tmp = tempnam(FILE_CACHE_LOCATION, 'RRS');
00175 
00176     if( !$tmp ) {
00177       throw new \Exception(_t('Socket Error. Unable to create temporary file name.'));
00178     }
00179 
00180     $result = file_put_contents($tmp, $body);
00181 
00182     if( $result === false ) {
00183       throw new \Exception(_t('Socket Error. Unable to write to temporary file.'));
00184     }
00185 
00186     // before we read it back in, try to free up as much memory as possible
00187     unset($body);
00188 
00189     $zp = gzopen($tmp, 'rb');
00190 
00191     $body = '';
00192     while (!gzeof($zp)) {
00193       $body .= gzread($zp, 1024);
00194     }
00195 
00196     gzclose($zp);
00197 
00198     // clean up the temp file
00199     if( file_exists($tmp) ) {
00200       unlink($tmp);
00201     }
00202 
00203     return $body;
00204 
00205   }
00206 
00207 }
00208 
00209 ?>

Generated on Sun Aug 4 2013 12:51:43 for Habari by  doxygen 1.7.1