osrs_username = $data['username']; $this->osrs_password = $data['password']; $this->osrs_key = $data['apikey']; $this->osrs_environment = $data['environment']; $this->osrs_protocol = $data['protocol']; $this->osrs_host = $data['host']; $this->osrs_port = '55000'; $this->osrs_sslPort = '55443'; $this->osrs_baseClassVersion = '2.8.0'; $this->osrs_version = 'XML:0.1'; $this->_verifySystemProperties (); $this->_opsHandler = new openSRS_ops; } // Class destructor public function __destruct () { } // Private functions private function _pullConfigVariables () { } private function _verifySystemProperties () { // Encryption verification 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_WARNING); die(); } elseif (!function_exists('openssl_open')) { $error_message = "PHP must be compiled using --with-openssl to use \"SSL\" encryption"; trigger_error ($error_message, E_USER_WARNING); die(); } } } // Send a command to the server public function send_cmd($request) { // make or get the socket filehandle if (!$this->init_socket() ) { trigger_error ("oSRS Error - Unable to establish socket: (". $this->_socketErrorNum .") ". $this->_socketErrorMsg, E_USER_WARNING); die(); } // Authenticate user $auth = $this->authenticate(); if (!$auth) { if ($this->_socket) $this->close_socket(); trigger_error ("oSRS Error - Authentication Error: ". $auth['error'], E_USER_WARNING); die(); } $this->send_data($request); $data = $this->read_data(); $num_matches = preg_match('/401<\/item>/', $data, $matches); if ($num_matches > 0) trigger_error("oSRS Error - Reseller username or osrs_key is incorrect, please check your config file."); return $data; } // Initialize a socket connection to the OpenSRS server private function init_socket() { if ($this->_socket) return true; if (!$this->osrs_environment) return false; if ($this->crypt_type == 'SSL') { $tempPortHand = $this->osrs_sslPort; $conType = 'ssl://'; } else { $tempPortHand = $this->osrs_port; $conType = ''; } $this->_socket = fsockopen($conType . $this->osrs_host, $tempPortHand, $this->_socketErrorNum, $this->_socketErrorMsg, $this->_socketTimeout); if (!$this->_socket) { return false; } else { return true; } } // Authenticate the connection with the username/private key private function authenticate() { if ($this->_authenticated || 'SSL' == $this->crypt_type) { return array('is_success' => true); } $promptXML = $this->read_data(); $prompt = $this->_opsHandler->decode($promptXML); if (isSet($prompt['response_code'])) { 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( 'protocol' => $this->osrs_protocol, 'action' => 'check', 'object' => 'version', 'attributes' => array( 'sender' => 'OpenSRS CLIENT', 'version' => $this->osrs_version, 'state' => 'ready' ) ); $xmlCMD = $this->_opsHandler->encode($cmd); $this->send_data($xmlCMD); $cmd = array( 'protocol' => $this->osrs_protocol, 'action' => 'authenticate', 'object' => 'user', 'attributes' => array( 'crypt_type' => strtolower($this->crypt_type), 'username' => $this->osrs_username, 'password' => $this->osrs_username ) ); $xmlCMD = $this->_opsHandler->encode($cmd); $this->send_data( $xmlCMD ); $challenge = $this->read_data(); // Sanity check to make sure that the osrs_key is all hex values $hex_check = ctype_xdigit($this->osrs_key); // Respond to the challenge with the MD5 checksum of the challenge. // ... and PHP's md5() doesn't return binary data, so // we need to pack that too if ($hex_check){ $this->_CBC = new openSRS_crypt(pack('H*', $this->osrs_key), $this->crypt_type); $response = pack('H*',md5($challenge)); $this->send_data($response); // Read the server's response to our login attempt (XML) $answerXML = $this->read_data(); $answer = $this->_opsHandler->decode($answerXML); if (substr($answer['response_code'],0,1)== '2') { $this->_authenticated = true; return true; } else { return false; } } else { trigger_error("oSRS Error - Please check the osrs_key value in the config file, it contains a non hexidecimal character."); } } // Close the socket connection private function close_socket() { fclose($this->_socket); if ($this->_CBC) $this->_CBC->_openSRS_crypt(); /* destructor */ $this->_CBC = false; $this->_authenticated = false; $this->_socket = false; } private function read_data() { $buf = $this->readData($this->_socket, $this->_socketReadTimeout); if (!$buf) { trigger_error ("oSRS Error - Read buffer is empty. Please make sure IP is whitelisted in RWI. Check the osrs_key and osrs_username in the config file as well.", E_USER_WARNING); $data = ""; } else { $data = $this->_CBC ? $this->_CBC->decrypt($buf) : $buf; } return $data; } private function send_data($message) { if ($this->_CBC) $message = $this->_CBC->encrypt($message); return $this->writeData( $this->_socket, $message ); } // Regex check for valid email private 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; } } /** * Writes a message to a socket (buffered IO) * @param int socket handle * @param string message to write */ private function writeData(&$fh,$msg) { $header = ""; $len = strlen($msg); switch ($this->crypt_type) { case 'SSL': $signature = md5(md5($msg.$this->osrs_key).$this->osrs_key); $header .= "POST / HTTP/1.0". $this->CRLF; $header .= "Content-Type: text/xml" . $this->CRLF; $header .= "X-Username: " . $this->osrs_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 ); } /** * Reads header data * @param int socket handle * @param int timeout for read * @return hash hash containing header key/value pairs */ private 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)) { trigger_error ("oSRS Error - UNEXPECTED READ: Unable to parse HTTP response code. Please make sure IP is whitelisted in RWI.", E_USER_WARNING); 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)) { trigger_error ("oSRS Error - UNEXPECTED READ: Error reading HTTP header.", E_USER_WARNING); 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->_opsHandler->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 { trigger_error ("oSRS Error - UNEXPECTED READ: No Content-Length.", E_USER_WARNING); return false; } /* read the empty line */ $line = fread($fh, 2); if ($this->_opsHandler->socketStatus($fh)) { return false; } if ($line!=$this->CRLF) { trigger_error ("oSRS Error - UNEXPECTED READ: No CRLF.", E_USER_WARNING); 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 */ private 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'}))) { if ($this->crypt_type == "SSL") trigger_error ("oSRS Error - UNEXPECTED ERROR: No Content-Length header provided! Please make sure IP is whitelisted in RWI.", E_USER_WARNING); else trigger_error ("oSRS Error - No Content-Length header returned. Please make sure IP is whitelisted in RWI. Check the API Key and Username.", E_USER_WARNING); } $len = (int)$header{'content-length'}; $line = ''; while (strlen($line) < $len) { $line .= fread($fh, $len); if ($this->_opsHandler->socketStatus($fh)) { return false; } } if ($line) { $buf = $line; } else { $buf = false; } if ('SSL' == $this->crypt_type) $this->close_socket(); return $buf; } // Helper functions public function convertXML2array ($xml) { $array = $this->_opsHandler->decode($xml); return $array; } }