Server IP : 213.176.29.180 / Your IP : 3.145.107.223 Web Server : Apache System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64 User : webtaragh ( 1001) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0755) : /home/webtaragh/public_html/whmcs/modules/addons/../gateways/../registrars/opensrs/ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
<?php /* ************************************************************************** * * OpenSRS-PHP * * Copyright (C) 2000-2004 Colin Viebrock * * Version 2.8.0 * 15-Dec-2004 * ************************************************************************** * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ************************************************************************** * * vim: set expandtab tabstop=4 shiftwidth=4: * $Id: openSRS_base.php,v 1.16.2.4 2004/12/07 20:27:22 cviebrock Exp $ * ************************************************************************** */ # assuming that the PEAR directory is within your path, otherwise change the path here if (file_exists(dirname(__FILE__).'/PEAR/PEAR.php')) { require_once dirname(__FILE__).'/PEAR/PEAR.php'; } if (file_exists(dirname(__FILE__).'/Crypt/CBC.php')) { require_once dirname(__FILE__).'/Crypt/CBC.php'; } # local requirements if (!class_exists("PEAR")) return false; require_once 'OPS.php'; require_once 'country_codes.php'; class openSRS_base extends PEAR { var $USERNAME = ''; var $HRS_USERNAME = ''; var $PRIVATE_KEY = ''; var $TEST_PRIVATE_KEY = ''; var $LIVE_PRIVATE_KEY = ''; var $HRS_PRIVATE_KEY = ''; var $VERSION = 'XML:0.1'; var $base_class_version = '2.8.0'; var $environment = 'LIVE'; /* 'TEST' or 'LIVE' or 'HRS' */ var $protocol = 'XCP'; /* 'XCP' or 'TPP' */ var $LIVE_host = 'rr-n1-tor.opensrs.net'; var $LIVE_port = 55000; var $LIVE_sslport = 55443; var $TEST_host = 'horizon.opensrs.net'; var $TEST_port = 55000; var $TEST_sslport = 55443; var $HRS_host; var $HRS_port; var $HRS_sslport; var $REMOTE_HOST; var $REMOTE_PORT; var $connect_timeout = 20; /* seconds */ var $read_timeout = 20; /* seconds */ var $log = array(); var $CRLF = "\r\n"; var $_socket = false; var $_socket_error_num = false; var $_socket_error_msg = false; var $_session_key = false; var $_authenticated = false; var $_OPS; var $_CBC; var $lookup_all_tlds = false; var $_CRYPT; var $_iv; var $crypt_type = 'SSL'; /* 'DES' or 'BLOWFISH' or 'SSL' */ var $crypt_mode = 'CBC'; /* only 'CBC' */ var $crypt_rand_source = MCRYPT_DEV_URANDOM; /* or MCRYPT_DEV_RANDOM or MCRYPT_RAND */ var $affiliate_id; var $PERMISSIONS = array ( 'f_modify_owner' => 1, 'f_modify_admin' => 2, 'f_modify_billing' => 4, 'f_modify_tech' => 8, 'f_modify_nameservers' => 16 ); var $REG_PERIODS = array ( 1 => '1 Year', 2 => '2 Years', 3 => '3 Years', 4 => '4 Years', 5 => '5 Years', 6 => '6 Years', 7 => '7 Years', 8 => '8 Years', 9 => '9 Years', 10 => '10 Years' ); var $UK_REG_PERIODS = array ( 2 => '2 Years' ); var $TV_REG_PERIODS = array ( 1 => '1 Year', 2 => '2 Years', 3 => '3 Years', 5 => '5 Years', 10 => '10 Years' ); var $TRANSFER_PERIODS = array ( 1 => '1 Year' ); var $OPENSRS_TLDS_REGEX = '(\.ca|\.(bc|ab|sk|mb|on|qc|nb|ns|pe|nf|nt|nv|yk)\.ca|\.com|\.net|\.org|\.co\.uk|\.org\.uk|\.tv|\.vc|\.cc|\.info|\.biz|\.name|\.us)'; var $CA_LEGAL_TYPES = array ( 'ABO' => 'Aboriginal', 'ASS' => 'Association', 'CCO' => 'Canadian Corporation', 'CCT' => 'Canadian Citizen', 'EDU' => 'Educational Institute', 'GOV' => 'Government', 'HOP' => 'Hospital', 'INB' => 'Indian Band', 'LAM' => 'Library, Archive or Museum', 'LGR' => 'Legal Respresentative', 'MAJ' => 'Her Majesty the Queen', 'OMK' => 'Protected by Trade-marks Act', 'PLT' => 'Political Party', 'PRT' => 'Partnership', 'RES' => 'Permanent Resident', 'TDM' => 'Trade-mark Owner', 'TRD' => 'Trade Union', 'TRS' => 'Trust' ); var $CA_LANGUAGE_TYPES = array ( 'EN' => 'English', 'FR' => 'French' ); var $CA_NATIONALITIES = array ( 'CND' => 'Canadian citizen', 'OTH' => 'Foreign citizenship', 'RES' => 'Canadian permanent resident' ); var $OPENSRS_ACTIONS = array ( 'get_domain' => true, 'get_userinfo' => true, 'modify_domain' => true, 'renew_domain' => true, 'register_domain' => true, 'get_nameserver' => true, 'create_nameserver' => true, 'modify_nameserver' => true, 'delete_nameserver' => true, 'get_subuser' => true, 'add_subuser' => true, 'modify_subuser' => true, 'delete_subuser' => true, 'change_password' => true, 'change_ownership' => true, 'set_cookie' => true, 'delete_cookie' => true, 'update_cookie' => true, 'sw_register_domain' => true, 'bulk_transfer_domain' => true, 'register_domain' => true, 'lookup_domain' => true, 'get_price_domain' => true, 'check_transfer_domain' => true, 'quit_session' => true, 'buy_webcert' => true, 'refund_webcert' => true, 'query_webcert' => true, 'cprefget_webcert' => true, 'cprefset_webcert' => true, 'cancel_pending_webcert' => true, 'update_webcert' => true, ); # # BASIC PUBLIC FUNCTIONS # /** * Class constructor * * Initialize variables, logs, etc. * * @param string Which environment to use (LIVE or TEST or HRS) * @param string Which protocol to use (XCP or TPP) * */ function __construct( $environment=NULL, $protocol=NULL, $regusername=NULL, $regprivatekey=NULL ) { $this->PEAR(); $this->crypt_type = strtoupper($this->crypt_type); if ('SSL' == $this->crypt_type) { if (!function_exists('version_compare') || version_compare('4.3', phpversion(), '>=')) { $error_message = 'PHP version must be v4.3+ (current version is ' . phpversion() . ') to use "SSL" encryption'; trigger_error ($error_message, E_USER_ERROR); $this->_log('i', $error_message); return false; } elseif (!function_exists('openssl_open')) { $error_message = 'PHP must be compiled using --with-openssl to use "SSL" encryption'; trigger_error ($error_message, E_USER_ERROR); $this->_log('i', $error_message); return false; } } $this->_log('i', 'OpenSRS Log:'); $this->_log('i', 'Initialized: '.date('r') ); $this->_OPS = new OPS; if ($environment) { $this->environment = strtoupper($environment); } if ($protocol) { $this->protocol = strtoupper($protocol); } $this->_log('i', 'Environment: '.$this->environment ); $this->_log('i', 'Protocol: '.$this->protocol ); $this->_CBC = false; $this->USERNAME = $regusername; $this->PRIVATE_KEY = $regprivatekey; } # # setProtocol() # Switch between XCP and TPP # function setProtocol( $proto ) { $proto = trim(strtoupper($proto)); switch ($proto) { case 'XCP': case 'TPP': $this->protocol = $proto; $this->_log('i', 'Set protocol: '.$this->protocol ); return true; break; default: return array( 'is_success' => false, 'error' => 'Invalid protocol: ' . $proto ); break; } } # # logout() # Send a 'quit' command to the server # function logout() { if ($this->_socket) { $this->send_cmd( array( 'action' => 'quit', 'object' => 'session' ) ); $this->close_socket(); } } # # send_cmd() # Send a command to the server # function send_cmd($request) { global $HTTP_SERVER_VARS; if (!is_array($request)) { $data = array( 'is_success' => false, 'response_code' => 400, 'response_text' => 'Invalid command (not an array): '.$request ); $this->_log('i',$data); return $data; } $action = $request['action']; $object = $request['object']; # prune any private data before sending down to the server # (eg. credit card numbers and information $this->prune_private_keys($request); # # Disable action checking. This means you don't need to update the code # each time OpenSRS adds a new command, but means you should be more # careful with your coding ... # # if (!isset($this->OPENSRS_ACTIONS[$action.'_'.$object])) { # $data = array( # 'is_success' => false, # 'response_code' => 400, # 'response_text' => 'Invalid command: '.$action.' '.$object # ); # $this->_log('i',$data); # return $data; # } # make or get the socket filehandle if (!$this->init_socket() ) { $data = array( 'is_success' => false, 'response_code' => 400, 'response_text' => 'Unable to establish socket: (' . $this->_socket_err_num . ') ' . $this->_socket_err_msg ); $this->_log('i',$data); return $data; } if ($this->environment == 'HRS') { $auth = $this->authenticate($this->HRS_USERNAME,$this->PRIVATE_KEY); } else { $auth = $this->authenticate($this->USERNAME,$this->PRIVATE_KEY); } if (!$auth['is_success']) { if ($this->_socket) { $this->close_socket(); } $data = array( 'is_success' => false, 'response_code' => 400, 'response_text' => 'Authentication Error: ' . $auth['error'] ); $this->_log('i',$data); return $data; } $request['registrant_ip'] = $HTTP_SERVER_VARS['REMOTE_ADDR']; if ( strstr($request['action'], 'lookup') ) { # lookups are treated specially $data = $this->lookup_domain( $request ); } else { # send request to server $this->send_data( $request ); $data = $this->read_data( ); } return $data; } # # validate() # Check data for validity # function validate($data,$params=array()) { # Country codes are needed for checking ... more reliable than /^[A-Z]{2}$/ include 'country_codes.php'; $missing_fields = $problem_fields = array(); $required_contact_fields = array ( 'first_name' => 'First Name', 'last_name' => 'Last Name', 'org_name' => 'Organization Name', 'address1' => 'Address1', 'city' => 'City', 'country' => 'Country', 'phone' => 'Phone', 'email' => 'E-Mail' ); $contact_types = array ( 'owner' => '', 'billing' => 'Billing' ); $required_fields = array ( 'reg_username' => 'Username', 'reg_password' => 'Password', 'domain' => 'Domain', ); if (isset($params['custom_tech_contact'])) { $contact_types['tech'] = 'Tech'; } # The primary and secondary nameservers are required. if ( isset($params['custom_nameservers']) && $data['reg_type']=='new' ) { if (!$data['fqdn1']) { $missing_fields[] = 'Primary DNS Hostname'; } if (!$data['fqdn2']) { $missing_fields[] = 'Secondary DNS Hostname'; } } # check the required fields foreach ($contact_types as $type=>$contact_type) { foreach ($required_contact_fields as $field=>$required_field) { $data[$type.'_'.$field] = trim($data[$type.'_'.$field]); if ($data[$type.'_'.$field] == '') { $missing_fields[] = $contact_type.' '.$required_field; } } $data[$type.'_country'] = strtolower($data[$type.'_country']); if ($data[$type.'_country']=='us' || $data[$type.'_country']=='ca') { if ($data[$type.'_postal_code']=='') { $missing_fields[] = $contact_type.' Zip/Postal Code'; } if ($data[$type.'_state']=='') { $missing_fields[] = $contact_type.' State/Province'; } } if (!isset($COUNTRY_CODES[$data[$type.'_country']])) { $problem_fields[$contact_type.' Country'] = $data[$type.'_country']; } if (!$this->check_email_syntax($data[$type.'_email'])) { $problem_fields[$contact_type.' Email'] = $data[$type.'_email']; } if (!preg_match('/^\+?[\d\s\-\.\(\)]+$/', $data[$type.'_phone'] )) { $problem_fields[$contact_type.' Phone'] = $data[$type.'_phone']; } } foreach ($required_fields as $field=>$required_field) { if ($data[$field] == '') { $missing_fields[] = $required_field; } } # these fields must have at least an alpha in them foreach ($data as $field=>$value) { if ($value=='') { continue; # skip blanks } if ($field=='first_name' || $field=='last_name' || $field=='org_name' || $field=='city' || $field=='state') { if (!preg_match('/[a-zA-Z]/', $value)) { $error_msg .= "Field $field must contain at least 1 alpha character.<br>\n"; } } } # take $missing_fields and add them to $error_msg foreach ($missing_fields as $field) { $error_msg .= "Missing field: $field.<br>\n"; } # check syntax on several fields # check domain, country, billing_country, email, billing_email, phone, # and billing_phone $domains = explode("\0", $data['domain'] ); foreach ($domains as $domain) { $syntaxError = $this->check_domain_syntax($domain); if ($syntaxError) { $problem_fields['Domain'] = $domain . " - " . $syntaxError; } } # print error if $problem_fields if (count(array_keys($problem_fields))) { foreach ($problem_fields as $field=>$problem) { # only show problem fields if it had a value. Otherwise, it # would have been caught above. if ($problem != '') { $error_msg .= "The field \"$field\" contained invalid characters: <i>$problem</i><br>\n"; } } } # insert other error checking here... if ($error_msg) { return ( array('error_msg' => $error_msg) ); } else { return ( array('is_success' => true) ); } } # # version() # return base class version # function version() { return 'OpenSRS-PHP Class version '.$this->base_class_version; } # # PRIVATE FUNCTIONS # # # init_socket() # Initialize a socket connection to the OpenSRS server # function init_socket() { if ($this->_socket) { return true; } if (!$this->environment) { return false; } $this->REMOTE_HOST = $this->{$this->environment.'_host'}; if ('SSL' == $this->crypt_type) { $this->REMOTE_PORT = $this->{$this->environment.'_sslport'}; } else { $this->REMOTE_PORT = $this->{$this->environment.'_port'}; } # create a socket $connection_protocol = ''; if ('SSL' == $this->crypt_type) { /* ssl:// requires PHP v4.3.0+ compiled with --with-openssl */ $connection_protocol = 'ssl://'; } $this->_socket = fsockopen($connection_protocol.$this->REMOTE_HOST, $this->REMOTE_PORT, $this->_socket_err_num, $this->_socket_err_msg, $this->connect_timeout ); if (!$this->_socket) { return false; } else { $this->_log('i','Socket initialized: ' . $this->REMOTE_HOST . ':' . $this->REMOTE_PORT ); return true; } } # # authenticate() # Authenticate the connection with the username/private key # function authenticate($username=false,$private_key=false) { if ($this->_authenticated || 'SSL' == $this->crypt_type) { return array('is_success' => true); } if (!$username) { return array( 'is_success' => false, 'error' => 'Missing reseller username' ); } else if (!$private_key) { return array( 'is_success' => false, 'error' => 'Missing private key' ); } $prompt = $this->read_data(); if ( $prompt['response_code'] == 555 ) { # the ip address from which we are connecting is not accepted return array( 'is_success' => false, 'error' => $prompt['response_text'] ); } else if ( !preg_match('/OpenSRS\sSERVER/', $prompt['attributes']['sender']) || substr($prompt['attributes']['version'],0,3) != 'XML' ) { return array( 'is_success' => false, 'error' => 'Unrecognized Peer' ); } # first response is server version $cmd = array( 'action' => 'check', 'object' => 'version', 'attributes' => array( 'sender' => 'OpenSRS CLIENT', 'version' => $this->VERSION, 'state' => 'ready' ) ); $this->send_data( $cmd ); $cmd = array( 'action' => 'authenticate', 'object' => 'user', 'attributes' => array( 'crypt_type' => strtolower($this->crypt_type), 'username' => $username, 'password' => $username ) ); $this->send_data( $cmd ); $challenge = $this->read_data( array('no_xml'=>true,'binary'=>true) ); # Respond to the challenge with the MD5 checksum of the challenge. # note the use of the no_xml => 1 set, because challenges are # are sent without XML # ... and PHP's md5() doesn't return binary data, so # we need to pack that too $this->_CBC = new Crypt_CBC(pack('H*', $private_key), $this->crypt_type ); $response = pack('H*',md5($challenge)); $this->send_data( $response, array('no_xml'=>true,'binary'=>true) ); # Read the server's response to our login attempt (XML) $answer = $this->read_data(); if (substr($answer['response_code'],0,1)== '2') { $this->_authenticated = true; return array('is_success' => true); } else { return array( 'is_success' => false, 'error' => 'Authentication failed' ); } } # # lookup_domain() # Special case for domain lookups # # # NOTE: I have changed the error codes returned by this function. # Instead of having all syntax errors return a 400 code, they return # codes in the range 490 to 499 range, depending on the type of error. # This makes it much easier to determine what *kind* of lookup error # happened, by having *us* parse through response_text for various strings. # # 490 No domain given # 491 TLD not supported # 492 Domain name too long # 493 Invalid characters # 499 Other error # # Syntax errors coming back from the server will likely still have error # code 400. Oh well. # function lookup_domain($lookupData) { $domain = strtolower($lookupData['attributes']['domain']); $affiliate_id = $lookupData['attributes']['affiliate_id']; if ($domain=='') { $data = array( 'is_success' => false, 'response_code' => 490, 'response_text' => "Invalid syntax: no domain given." ); return $data; } $syntaxError = $this->check_domain_syntax($domain); if ($syntaxError) { # START of new error stuff $code = 499; if (strstr($syntaxError, 'Top level domain in')) { $code = 491; } else if (strstr($syntaxError, 'Domain name exceeds maximum length')) { $code = 492; } else if (strstr($syntaxError, 'Invalid domain format')) { $code = 493; } # END of new error stuff $data = array( 'is_success' => false, 'response_code' => $code, 'response_text' => "Invalid domain syntax for $domain: $syntaxError." ); return $data; } # attempt to find other available matches if requested in conf file $domains = array(); preg_match('/(.+)'.$this->OPENSRS_TLDS_REGEX.'$/', $domain, $temp); $base = $temp[1]; $tld = $temp[2]; $relatedTLDs = $this->getRelatedTLDs( $tld ); if ($this->lookup_all_tlds && is_array($relatedTLDs)) { $domains = array(); foreach($relatedTLDs as $stem) { $domains[] = $base.$stem; } } else { $domains[] = $domain; } $data = array(); foreach($domains as $local_domain) { $lookupData['attributes']['domain'] = $local_domain; # send request to server $this->send_data( $lookupData ); $answer = $this->read_data( ); if ( $answer['attributes']['status'] && stristr($answer['attributes']['status'],'available') && !stristr($local_domain,$domain) ) { $data['attributes']['matches'][] = $local_domain; } # The original domain in the lookup determines # the overall return values if ($local_domain==$domain) { $data['is_success'] = $answer['is_success']; $data['response_code'] = $answer['response_code']; $data['response_text'] = $answer['response_text']; $data['attributes']['status'] = $answer['attributes']['status']; $data['attributes']['upg_to_subdomain'] = $answer['attributes']['upg_to_subdomain']; $data['attributes']['reason'] = $answer['attributes']['reason']; } } return $data; } # # close_socket() # Close the socket connection # function close_socket() { fclose($this->_socket); if ($this->_CBC) { $this->_CBC->_Crypt_CBC(); /* destructor */ } $this->_CBC = false; $this->_authenticated = false; $this->_socket = false; $this->_log('i','Socket closed'); } # # read_data() # Reads a response from the server # function read_data($args=array()) { $buf = $this->readData($this->_socket, $this->read_timeout); if (!$buf) { $data = array('error' => 'Read error'); $this->_log('i',$data); } else { $data = $this->_CBC ? $this->_CBC->decrypt($buf) : $buf; if (!$args['no_xml']) { $data = $this->_OPS->decode($data); } if ($args['binary']) { $temp = unpack('H*temp', $data); $this->_log('r', 'BINARY: ' . $temp['temp'] ); } else { $this->_log('r',$data); } } return $data; } # # send_data() # Sends request to the server # function send_data($message, $args=array()) { if (!$args['no_xml']) { $message['protocol'] = $this->protocol; $data_to_send = $this->_OPS->encode( $message ); # have to lowercase the action and object keys # because OPS.pm uppercases them $message['action'] = strtolower($message['action']); $message['object'] = strtolower($message['object']); } else { # no XML encoding $data_to_send = $message; } if ($args['binary']) { $temp = unpack('H*temp', $message); $this->_log('s', 'BINARY: ' . $temp['temp'] ); } else { $this->_log('s', $message); } if ($this->_CBC) { $data_to_send = $this->_CBC->encrypt($data_to_send); } return $this->writeData( $this->_socket, $data_to_send ); } # # check_email_syntax() # Regex check for valid email # function check_email_syntax($email) { if ( preg_match('/(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/', $email) || !preg_match('/^\S+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/', $email) ) { return false; } else { return true; } } # # check_domain_syntax() # Regex check for valid domain # function check_domain_syntax($domain) { $domain = strtolower($domain); $MAX_UK_LENGTH = 61; $MAX_NSI_LENGTH = 67; if (substr($domain,-3)=='.uk') { $maxLengthForThisCase = $MAX_UK_LENGTH; } else { $maxLengthForThisCase = $MAX_NSI_LENGTH; } if (strlen($domain) > $maxLengthForThisCase) { return "Domain name exceeds maximum length for registry ($maxLengthForThisCase)"; } else if (!preg_match('/'.$OPENSRS_TLDS_REGEX.'$/', $domain)) { return "Top level domain in \"$domain\" is unavailable"; } else if (!preg_match('/^[a-zA-Z0-9][.a-zA-Z0-9\-]*[a-zA-Z0-9]'.$this->OPENSRS_TLDS_REGEX.'$/', $domain)) { return "Invalid domain format (try something similar to \"yourname.com\")"; } return false; } # # prune_private_keys() # Recursively remove keys that start with 'p_' from an array # function prune_private_keys(&$data) { if (is_array($data) || is_object($data)) { foreach($data as $key=>$value) { if (substr($key,0,2)=='p_') { unset($data[$key]); } else if (is_array($value)) { $this->prune_private_keys($value); } } } } # # getRelatedTLDs() # function getRelatedTLDs($tld) { if (is_array($this->RELATED_TLDS)) { foreach($this->RELATED_TLDS as $relatedTLDs) { foreach ($relatedTLDs as $TLDstring) { if ($TLDstring==$tld) { return $relatedTLDs; } } } } return array(); } # # _log() # Internal logging method # function _log($type,$data) { $types = array( 'i' => 'Info', 'r' => 'Read', 's' => 'Sent' ); $temp = sprintf("[ %s%s ]\n", strtoupper($types[$type]), (($type!='i' && $this->_CBC) ? ' - '.$this->crypt_type.' ENCRYPTED' : '') ); ob_start(); print_r($data); $temp .= ob_get_contents() . "\n"; ob_end_clean(); $this->log[] = $temp; } # # showlog() # output the debugging log # function showlog() { echo '<PRE>'; foreach ($this->log as $line) { echo htmlEntities($line) . "\n"; } echo '</PRE>'; } /** * Writes a message to a socket (buffered IO) * * @param int socket handle * * @param string message to write * */ function writeData(&$fh,$msg) { $header = ""; $len = strlen($msg); switch ($this->crypt_type) { case 'SSL': $signature = md5(md5($msg.$this->PRIVATE_KEY).$this->PRIVATE_KEY); $header .= "POST / HTTP/1.0". $this->CRLF; $header .= "Content-Type: text/xml" . $this->CRLF; $header .= "X-Username: " . $this->USERNAME . $this->CRLF; $header .= "X-Signature: " . $signature . $this->CRLF; $header .= "Content-Length: " . $len . $this->CRLF . $this->CRLF; break; case 'BLOWFISH': case 'DES': default: $header .= "Content-Length: " . $len . $this->CRLF . $this->CRLF; break; } fputs($fh, $header); fputs($fh, $msg, $len ); if ('SSL' == $this->crypt_type) { $this->_OPS->_log('http', 'w', $header.$msg); } $this->_OPS->_log('raw', 'w', $msg, $len); } /** * Reads header data * * @param int socket handle * * @param int timeout for read * * @return hash hash containing header key/value pairs * */ function readHeader($fh, $timeout=5) { $header = array(); switch ($this->crypt_type) { case 'SSL': /* HTTP/SSL connection method */ $http_log =''; $line = fgets($fh, 4000); $http_log .= $line; if (!preg_match('/^HTTP\/1.1 ([0-9]{0,3}) (.*)\r\n$/',$line, $matches)) { $this->_OPS->_log('raw', 'e', 'UNEXPECTED READ: Unable to parse HTTP response code' ); $this->_OPS->_log('raw', 'r', $line); return false; } $header['http_response_code'] = $matches[1]; $header['http_response_text'] = $matches[2]; while ($line != $this->CRLF) { $line = fgets($fh, 4000); $http_log .= $line; if (feof($fh)) { $this->_OPS->_log('raw', 'e', 'UNEXPECTED READ: Error reading HTTP header' ); $this->_OPS->_log('raw', 'r', $line); return false; } $matches = explode(': ', $line, 2); if (sizeof($matches) == 2) { $header[trim(strtolower($matches[0]))] = $matches[1]; } } $header['full_header'] = $http_log; break; case 'BLOWFISH': case 'DES': default: /* socket (old-style) connection */ $line = fgets($fh, 4000); if ($this->_OPS->socketStatus($fh)) { return false; } if (preg_match('/^\s*Content-Length:\s+(\d+)\s*\r\n/i', $line, $matches ) ) { $header['content-length'] = (int)$matches[1]; } else { $this->_OPS->_log('raw', 'e', 'UNEXPECTED READ: No Content-Length' ); $this->_OPS->_log('raw', 'r', $line); return false; } /* read the empty line */ $line = fread($fh, 2); if ($this->_OPS->socketStatus($fh)) { return false; } if ($line!=$this->CRLF) { $this->_OPS->_log('raw', 'e', 'UNEXPECTED READ: No CRLF'); $this->_OPS->_log('raw', 'r', $line); return false; } break; } return $header; } /** * Reads data from a socket * * @param int socket handle * * @param int timeout for read * * @return mixed buffer with data, or an error for a short read * */ function readData(&$fh, $timeout=5) { $len = 0; /* PHP doesn't have timeout for fread ... we just set the timeout for the socket */ socket_set_timeout($fh, $timeout); $header = $this->readHeader($fh, $timeout); if (!$header || !isset($header['content-length']) || (empty($header['content-length']))) { $this->_OPS->_log('raw', 'e', 'UNEXPECTED ERROR: No Content-Length header provided!' ); } $len = (int)$header['content-length']; $line = ''; while (strlen($line) < $len) { $line .= fread($fh, $len); if ($this->_OPS->socketStatus($fh)) { return false; } } if ($line) { $buf = $line; $this->_OPS->_log('raw', 'r', $line); } else { $buf = false; $this->_OPS->_log('raw', 'e', 'NEXT LINE SHORT READ (should be '.$len.')' ); $this->_OPS->_log('raw', 'r', $line); } if ('SSL' == $this->crypt_type) { $this->_OPS->_log('http', 'r', $header['full_header'].$line); $this->close_socket(); } return $buf; } }