* @license GNU General Public License version 2 or later; see LICENSE.txt * @param Registry $options Client options object. * @param mixed $adapters Adapter (string) or queue of adapters (array) to use for communication. * * @return Http Joomla Http class * * @throws \RuntimeException * * @since 3.0.0 */ static function getHttp($options = [], $adapters = null){ if(JVM_VERSION < 4){ if (empty($options)) { $options = new Registry; } if (!$driver = JHttpFactory::getAvailableDriver($options, $adapters)) { throw new \RuntimeException('No transport driver available.'); } return new Http($options, $driver); } else { if ($options === null) { $options = array(); } else if (!\is_array($options) && !($options instanceof \ArrayAccess)) { throw new \InvalidArgumentException( 'The options param must be an array or implement the ArrayAccess interface.' ); } // Set default userAgent if nothing else is set if (!isset($options['userAgent'])) { $version = new Version; $options['userAgent'] = $version->getUserAgent('Joomla', true, false); } if (!$driver = JHttpFactory::getAvailableDriver($options, $adapters)) { throw new \RuntimeException('No transport driver available.'); } return new Http($options, $driver); } } var $handle = null; /** * Clears the output buffer, sends a http status code and a content if given * @static * @param int $http_status * @param string $mime_type * @param string $content */ function sendHeaderAndContent( $http_status=200, $content='', $mime_type='text/html' ) { // Clear all Joomla header and buffer stuff while( @ob_end_clean() ); $http_status = intval( $http_status ); @header("HTTP/1.0 $http_status"); if( $mime_type ) { @header( "Content-type: $mime_type; charset=UTF-8" ); } elseif( $mime_type != '' ) { @header( "Content-type: text/html; charset=UTF-8" ); } if( $content ) { echo $content; } } /** * This is a general function to safely open a connection to a server, * post data when needed and read the result. * Tries using cURL and switches to fopen/fsockopen if cURL is not available * @since VirtueMart 1.1.0 * @static * @param string $url * @param string $postData * @param array $headers * @param resource $fileToSaveData * @return mixed */ static function handleCommunication( $url, $postData='', $headers=array(), $fileToSaveData=null ) { $urlParts = parse_url( $url ); if( !isset( $urlParts['port'] )) $urlParts['port'] = 80; if( !isset( $urlParts['scheme'] )) $urlParts['scheme'] = 'http'; if( isset( $urlParts['query'] )){ $urlParts['query'] = '?'.$urlParts['query']; if( isset( $urlParts['path'] )) $urlParts['path'] = $urlParts['path'].$urlParts['query']; } $vm_proxy_url = VmConfig::get('conf_VM_PROXY_URL',''); // Check proxy if( trim( $vm_proxy_url ) != '') { if( !stristr($vm_proxy_url, 'http')) { $proxyURL['host'] = $vm_proxy_url; $proxyURL['scheme'] = 'http'; } else { $proxyURL = parse_url($vm_proxy_url); } } else { $proxyURL = ''; } if( function_exists( "curl_init" ) && function_exists( 'curl_exec' ) ) { $CR = curl_init(); curl_setopt($CR, CURLOPT_URL, $url); // just to get sure the script doesn't die curl_setopt($CR, CURLOPT_TIMEOUT, 30 ); if( !empty( $headers )) { // Add additional headers if provided curl_setopt($CR, CURLOPT_HTTPHEADER, $headers); } curl_setopt($CR, CURLOPT_FAILONERROR, true); if( $postData ) { curl_setopt($CR, CURLOPT_POSTFIELDS, $postData ); curl_setopt($CR, CURLOPT_POST, 1); } if( is_resource($fileToSaveData)) { curl_setopt($CR, CURLOPT_FILE, $fileToSaveData ); } else { curl_setopt($CR, CURLOPT_RETURNTRANSFER, 1); } // Do we need to set up the proxy? if( !empty($proxyURL) ) { // $vmLogger->debug( 'Setting up proxy: '.$proxyURL['host'].':'.VM_PROXY_PORT ); //curl_setopt($CR, CURLOPT_HTTPPROXYTUNNEL, true); curl_setopt($CR, CURLOPT_PROXY, $proxyURL['host'] ); curl_setopt($CR, CURLOPT_PROXYPORT, VM_PROXY_PORT ); // Check if the proxy needs authentication if( trim( @VM_PROXY_USER ) != '') { // $vmLogger->debug( 'Using proxy authentication!' ); curl_setopt($CR, CURLOPT_PROXYUSERPWD, VM_PROXY_USER.':'.VM_PROXY_PASS ); } } if( $urlParts['scheme'] == 'https') { // No PEER certificate validation...as we don't have // a certificate file for it to authenticate the host www.ups.com against! curl_setopt($CR, CURLOPT_SSL_VERIFYPEER, 0); } $result = curl_exec( $CR ); $error = curl_error( $CR ); if( !empty( $error ) && stristr( $error, '502') && !empty( $proxyURL )) { // $vmLogger->debug( 'Switching to NTLM authenticaton.'); curl_setopt( $CR, CURLOPT_PROXYAUTH, CURLAUTH_NTLM ); $result = curl_exec( $CR ); $error = curl_error( $CR ); } curl_close( $CR ); if( !empty( $error )) { return false; } else { return $result; } } else { if( $postData ) { if( !empty( $proxyURL )) { // If we have something to post we need to write into a socket if( $proxyURL['scheme'] == 'https') { $protocol = 'ssl'; } else { $protocol = 'http'; } $fp = fsockopen("$protocol://".$proxyURL['host'], VM_PROXY_PORT, $errno, $errstr, $timeout = 30); } else { // If we have something to post we need to write into a socket if( $urlParts['scheme'] == 'https') { $protocol = 'ssl'; } else { $protocol = $urlParts['scheme']; } $fp = fsockopen("$protocol://".$urlParts['host'], $urlParts['port'], $errno, $errstr, $timeout = 30); } } else { if( !empty( $proxyURL )) { // Do a read-only fopen transaction $fp = fopen( $proxyURL['scheme'].'://'.$proxyURL['host'].':'.VM_PROXY_PORT, 'rb' ); } else { // Do a read-only fopen transaction $fp = fopen( $urlParts['scheme'].'://'.$urlParts['host'].':'.$urlParts['port'].$urlParts['path'], 'rb' ); } } if(!$fp) { //error tell us vmWarn( 'Possible server error! - '.$errstr .'('.$errno.')\n' ); return false; } else { vmdebug( 'Connection opened to '.$urlParts['host']); } if( $postData ) { //send the server request if( !empty( $proxyURL )) { fputs($fp, "POST ".$urlParts['host'].':'.$urlParts['port'].$urlParts['path']." HTTP/1.0\r\n"); fputs($fp, "Host: ".$proxyURL['host']."\r\n"); if( trim( @VM_PROXY_USER )!= '') { fputs($fp, "Proxy-Authorization: Basic " . base64_encode (VM_PROXY_USER.':'.VM_PROXY_PASS ) . "\r\n\r\n"); } } else { fputs($fp, 'POST '.$urlParts['path']." HTTP/1.0\r\n"); fputs($fp, 'Host:'. $urlParts['host']."\r\n"); } fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); fputs($fp, "Content-length: ".strlen($postData)."\r\n"); fputs($fp, "Connection: close\r\n\r\n"); fputs($fp, $postData . "\r\n\r\n"); } else { if( !empty( $proxyURL )) { fputs($fp, "GET ".$urlParts['host'].':'.$urlParts['port'].$urlParts['path']." HTTP/1.0\r\n"); fputs($fp, "Host: ".$proxyURL['host']."\r\n"); if( trim( @VM_PROXY_USER )!= '') { fputs($fp, "Proxy-Authorization: Basic " . base64_encode (VM_PROXY_USER.':'.VM_PROXY_PASS ) . "\r\n\r\n"); } } else { fputs($fp, 'GET '.$urlParts['path']." HTTP/1.0\r\n"); fputs($fp, 'Host:'. $urlParts['host']."\r\n"); } } // Add additional headers if provided foreach( $headers as $header ) { fputs($fp, $header."\r\n"); } $data = ""; while (!feof($fp)) { $data .= @fgets ($fp, 4096); } fclose( $fp ); // If didnt get content-length, something is wrong, return false. if ( trim($data) == '' ) { vmWarn('An error occured while communicating with the server '.$urlParts['host'].'. It didn\'t reply (correctly). Please try again later, thank you.' ); return false; } $result = trim( $data ); if( is_resource($fileToSaveData )) { fwrite($fileToSaveData, $result ); return true; } else { return $result; } } } /** * Set headers and send the file to the client * * @author Andreas Gohr * @param string The full path to the file * @param string The Mime Type of the file */ function sendFile($file,$mime, $overrideFileName='') { // send headers header("Content-Type: $mime"); list($start,$len) = VmConnector::http_rangeRequest(filesize($file)); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header('Accept-Ranges: bytes'); //application mime type is downloadable if(strtolower(substr($mime,0,11)) == 'application') { if( $overrideFileName == '') { $filename = basename($file); } else { $filename = $overrideFileName; } header('Content-Disposition: attachment; filename="'.$filename.'";'); } $chunksize = 1*(1024*1024); // send file contents $fp = @fopen($file,"rb"); if($fp) { fseek($fp,$start); //seek to start of range $chunk = ($len > $chunksize) ? $chunksize : $len; while (!feof($fp) && $chunk > 0) { @set_time_limit(); // large files can take a lot of time print fread($fp, $chunk); flush(); $len -= $chunk; $chunk = ($len > $chunksize) ? $chunksize : $len; } fclose($fp); }else { header("HTTP/1.0 500 Internal Server Error"); print "Could not read $file - bad permissions?"; JFactory::getApplication()->close(true); } } /** * Checks and sets headers to handle range requets * * @author Andreas Gohr * @return array The start byte and the amount of bytes to send * @param int The file size */ function http_rangeRequest($size, $exitOnError=true ) { if(!isset($_SERVER['HTTP_RANGE'])) { // no range requested - send the whole file header("Content-Length: $size"); return array(0,$size); } $t = explode('=', $_SERVER['HTTP_RANGE']); if (!$t[0]=='bytes') { // we only understand byte ranges - send the whole file header("Content-Length: $size"); return array(0,$size); } $r = explode('-', $t[1]); $start = (int)$r[0]; $end = (int)$r[1]; if (!$end) $end = $size - 1; if ($start > $end || $start > $size || $end > $size) { if( $exitOnError ) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); print 'Bad Range Request!'; JFactory::getApplication()->close(true); } else { return array(0,$size); } } $tot = $end - $start + 1; header('HTTP/1.1 206 Partial Content'); header("Content-Range: bytes {$start}-{$end}/{$size}"); header("Content-Length: $tot"); return array($start,$tot); } } // pure php no closing tag