/plugins/registrar/_opensrs-php/OPS.php
PHP | 667 lines | 341 code | 148 blank | 178 comment | 49 complexity | e22f0f80a6fc2a3568edf9fb281e360b MD5 | raw file
- <?php
- /*
- **************************************************************************
- *
- * OpenSRS-PHP
- *
- * Copyright (C) 2000, 2001, 2002, 2003 Colin Viebrock
- * and easyDNS Technologies Inc.
- *
- **************************************************************************
- *
- * 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: OPS.php,v 1.1 2004/09/30 09:25:23 Tony Exp $
- *
- **************************************************************************
- */
- require_once 'PEAR.php';
- class OPS extends PEAR {
- var $_OPS_VERSION = '0.9';
- var $_OPT = '';
- var $_SPACER = ' '; /* indent character */
- var $_CRLF = "\n";
- var $_MSGTYPE_STD = 'standard';
- var $_SESSID;
- var $_MSGCNT;
- var $CRLF = "\r\n";
- var $_log = array();
- var $_data;
- var $_pointers;
- var $_last_was_data_block;
- /**
- * Class constructor
- *
- * Initialize variables, logs, etc.
- *
- * @param array allows for setting various options (right now, just whether
- * to use compression or not on the generated XML)
- */
- function OPS($args=false)
- {
- $this->PEAR();
- if (is_array($args)) {
- if ($args['option']=='compress') {
- $this->_OPT = 'compress';
- $this->_SPACER = '';
- $this->_CRLF = '';
- }
- }
- $this->_SESSID = getmypid();
- $this->_MSGCNT = 0;
- $this->_log('raw','i','OPS Raw Log:');
- $this->_log('raw','i','Initialized '.date('r') );
- $this->_log('xml','i','OPS XML Log:');
- $this->_log('xml','i','Initialized '.date('r') );
- }
- /**
- * Writes a message to a socket (buffered IO)
- *
- * @param int socket handle
- *
- * @param string message to write
- *
- */
- function writeData(&$fh,$msg)
- {
- $len = strlen($msg);
- fputs($fh, 'Content-Length: ' . $len . $this->CRLF . $this->CRLF);
- fputs($fh, $msg, $len );
- $this->_log('raw', 'w', $msg, $len);
- }
- /**
- * Encodes and writes a message to a socket
- *
- * @param int socket handle
- *
- * @param string message to encode and write
- *
- */
- function writeMessage(&$fh, $hr )
- {
- $msg = $this->encode( $hr );
- $this->writeData($fh, $msg );
- }
- /**
- * 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);
- $line = fgets($fh, 4000);
- if ($this->socketStatus($fh)) {
- return false;
- }
- if (!$len && preg_match('/^\s*Content-Length:\s+(\d+)\s*\r\n/i', $line, $matches ) ) {
- $len = (int)$matches[1];
- } else {
- $this->_log('raw', 'e', 'UNEXPECTED READ: No Content-Length' );
- $this->_log('raw', 'r', $line);
- return false;
- }
- /* read the empty line */
- $line = fread($fh, 2);
- if ($this->socketStatus($fh)) {
- return false;
- }
- if ($line!=$this->CRLF) {
- $this->_log('raw', 'e', 'UNEXPECTED READ: No CRLF');
- $this->_log('raw', 'r', $line);
- return false;
- }
- $line = '';
- while (strlen($line) < $len) {
- $line .= fread($fh, $len);
- if ($this->socketStatus($fh)) {
- return false;
- }
- }
- if ($line) {
- $buf = $line;
- $this->_log('raw', 'r', $line);
- } else {
- $buf = false;
- $this->_log('raw', 'e', 'NEXT LINE SHORT READ (should be '.$len.')' );
- $this->_log('raw', 'r', $line);
- }
- return $buf;
- }
- /**
- * Reads and decodes data from a socket
- *
- * @param int socket handle
- *
- * @param int timeout for read
- *
- * @return mixed associative array of data, or an error
- *
- */
- function readMessage(&$fh, $timeout=5)
- {
- $buf = $this->readData($fh, $timeout);
- return ( $buf ? $this->decode($buf) : false );
- }
- /**
- * Checks a socket for timeout or EOF
- *
- * @param int socket handle
- *
- * @return boolean true if the socket has timed out or is EOF
- *
- */
- function socketStatus(&$fh)
- {
- $return = false;
- if (is_resource($fh)) {
- $temp = socket_get_status($fh);
- if ($temp['timed_out']) {
- $this->_log('raw', 'e', 'SOCKET TIMED OUT');
- $return = true;
- }
- if ($temp['eof']) {
- $this->_log('raw', 'e', 'SOCKET EOF');
- $return = true;
- }
- unset($temp);
- }
- return $return;
- }
- /**
- * Internal method to generate error codes hashes
- *
- * @param int error code
- *
- * @param string error message
- *
- * @return array error hash
- *
- */
- function _opsError($err_code,$err_text)
- {
- return array(
- 'response_code' => $err_code,
- 'response_text' => $err_text,
- 'is_success' => 0
- );
- }
- #
- # DECODING METHODS
- # Converts XML OPS messages into PHP data
- #
- /**
- * Accepts an OPS protocol message or an file handle
- * and decodes the data into a PHP array
- *
- * @param string OPS message
- *
- * @return mixed PHP array, or error
- *
- */
- function decode($in)
- {
- $ops_msg = '';
- /* determine if we were passed a string or file handle */
- if (is_resource($in)) {
- # read the file into a string, then process as usual
- while (!feof($in)) {
- $ops_msg .= fgets($in, 400);
- }
- } else {
- $ops_msg = $in;
- }
- /* log it first */
- $this->_log('xml', 'r', $ops_msg);
- /* decode and return */
- return $this->XML2PHP($ops_msg);
- }
- /**
- * XML Parser that converts an OPS protocol message into a PHP array
- *
- * @param string OPS message
- *
- * @return mixed PHP array, or error
- *
- */
- function XML2PHP($msg) {
- $this->_data = NULL;
- $xp = xml_parser_create();
- xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
- xml_parser_set_option($xp, XML_OPTION_SKIP_WHITE, true);
- xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING, 'ISO-8859-1');
- if (!xml_parse_into_struct($xp,$msg,$vals,$index)) {
- $error = sprintf('XML error: %s at line %d',
- xml_error_string(xml_get_error_code($xp)),
- xml_get_current_line_number($xp)
- );
- xml_parser_free($xp);
- return $this->raiseError($error);
- }
- xml_parser_free($xp);
- $temp = $depth = array();
- foreach($vals as $value) {
- switch ($value['tag']) {
- case 'OPS_envelope':
- case 'header':
- case 'body':
- case 'data_block':
- break;
- case 'version':
- case 'msg_id':
- case 'msg_type':
- $key = '_OPS_' . $value['tag'];
- $temp[$key] = $value['value'];
- break;
- case 'item':
- $key = $value['attributes']['key'];
- switch ($value['type']) {
- case 'open':
- array_push($depth, $key);
- break;
- case 'complete':
- array_push($depth, $key);
- $p = join('::',$depth);
- $temp[$p] = $value['value'];
- array_pop($depth);
- break;
- case 'close':
- array_pop($depth);
- break;
- }
- break;
- case 'dt_assoc':
- case 'dt_array':
- break;
- }
- }
- foreach ($temp as $key=>$value) {
- $levels = explode('::',$key);
- $num_levels = count($levels);
- if ($num_levels==1) {
- $this->_data[$levels[0]] = $value;
- } else {
- $pointer = &$this->_data;
- for ($i=0; $i<$num_levels; $i++) {
- if ( !isset( $pointer[$levels[$i]] ) ) {
- $pointer[$levels[$i]] = array();
- }
- $pointer = &$pointer[$levels[$i]];
- }
- $pointer = $value;
- }
- }
- return ($this->_data);
- }
- #
- # ENCODING METHODS
- # Converts PHP data into XML OPS messages
- #
- /**
- * Converts a PHP array into an OPS message
- *
- * @param array PHP array
- *
- * @return string OPS XML message
- *
- */
- function encode($array)
- {
- $this->_MSGCNT++;
- $msg_id = $this->_SESSID + $this->_MSGCNT; /* addition removes the leading zero */
- $msg_type = $this->_MSGTYPE_STD;
- if ($array['protocol']) {
- $array['protocol'] = strtoupper($array['protocol']);
- }
- if ($array['action']) {
- $array['action'] = strtoupper($array['action']);
- }
- if ($array['object']) {
- $array['object'] = strtoupper($array['object']);
- }
- $xml_data_block = $this->PHP2XML($array);
- $ops_msg = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>' . $this->_CRLF .
- '<!DOCTYPE OPS_envelope SYSTEM "ops.dtd">' . $this->_CRLF .
- '<OPS_envelope>' . $this->_CRLF .
- $this->_SPACER . '<header>' . $this->_CRLF .
- $this->_SPACER . $this->_SPACER . '<version>' . $this->_OPS_VERSION . '</version>' . $this->_CRLF .
- $this->_SPACER . $this->_SPACER . '<msg_id>' . $msg_id . '</msg_id>' . $this->_CRLF .
- $this->_SPACER . $this->_SPACER . '<msg_type>' . $msg_type . '</msg_type>' . $this->_CRLF .
- $this->_SPACER . '</header>' . $this->_CRLF .
- $this->_SPACER . '<body>' . $this->_CRLF .
- $xml_data_block . $this->_CRLF .
- $this->_SPACER . '</body>' . $this->_CRLF .
- '</OPS_envelope>';
- # log it
- $this->_log('xml', 'w', $ops_msg);
- return $ops_msg;
- }
- /**
- * Converts a PHP array into an OPS data_block tag
- *
- * @param array PHP array
- *
- * @return string OPS data_block tag
- *
- */
- function PHP2XML($data)
- {
- return str_repeat($this->_SPACER,2) . '<data_block>' .
- $this->_convertData($data, 3) .
- $this->_CRLF . str_repeat($this->_SPACER,2) . '</data_block>';
- }
- /**
- * Recursivly converts PHP data into XML
- *
- * @param mixed PHP array or data
- *
- * @param int ident level
- *
- * @return string XML string
- *
- */
- function _convertData(&$array, $indent=0)
- {
- $string = '';
- $IND = str_repeat($this->_SPACER,$indent);
- if (is_array($array)) {
- if ($this->_is_assoc($array)) { # HASH REFERENCE
- $string .= $this->_CRLF . $IND . '<dt_assoc>';
- $end = '</dt_assoc>';
- } else { # ARRAY REFERENCE
- $string .= $this->_CRLF . $IND . '<dt_array>';
- $end = '</dt_array>';
- }
- foreach ($array as $k=>$v) {
- $indent++;
- /* don't encode some types of stuff */
- if ((gettype($v)=='resource') || (gettype($v)=='user function') || (gettype($v)=='unknown type')) {
- continue;
- }
- $string .= $this->_CRLF . $IND . '<item key="' . $k . '"';
- if (gettype($v)=='object' && get_class($v)) {
- $string .= ' class="' . get_class($v) . '"';
- }
- $string .= '>';
- if (is_array($v) || is_object($v)) {
- $string .= $this->_convertData($v, $indent+1);
- $string .= $this->_CRLF . $IND . '</item>';
- } else {
- $string .= $this->_quoteXMLChars($v) . '</item>';
- }
- $indent--;
- }
- $string .= $this->_CRLF . $IND . $end;
- } else { # SCALAR
- $string .= $this->_CRLF . $IND . '<dt_scalar>' .
- $this->_quoteXMLChars($array) . '</dt_scalar>';
- }
- return $string;
- }
- /**
- * Quotes special XML characters
- *
- * @param string string to quote
- *
- * @return string quoted string
- *
- */
- function _quoteXMLChars($string)
- {
- $search = array ('&', '<', '>', "'", '"');
- $replace = array ('&', '<', '>', ''', '"');
- $string = str_replace($search, $replace, $string);
- $string = utf8_encode($string);
- return $string;
- }
- /**
- * Determines if an array is associative or not, since PHP
- * doesn't really distinguish between the two, but Perl/OPS does
- *
- * @param array array to check
- *
- * @return boolean true if the array is associative
- *
- */
- function _is_assoc(&$array)
- {
- if (is_array($array)) {
- foreach ($array as $k=>$v) {
- if (!is_int($k)) {
- return true;
- }
- }
- }
- return false;
- }
- /**
- * Internal loggging method
- *
- * @param string which log to log to
- *
- * @param string type of log message ('r'ead, 'w'rite, 'i'nfo or 'e'rror)
- *
- * @param int message
- *
- */
- function _log($log, $type, $msg)
- {
- $types = array(
- 'r' => 'read',
- 'w' => 'write',
- 'e' => 'error',
- 'i' => 'info'
- );
- if ($log=='xml') {
- $this->log[$log][] = sprintf("[% 6s:%06d] %s\n",
- strtoupper($types[$type]),
- ($type=='e' || $type=='i') ? 0 : strlen($msg),
- $msg
- );
- } else {
- $this->log[$log][] = sprintf("[% 6s:%06d] %s\n",
- strtoupper($types[$type]),
- ($type=='e' || $type=='i') ? 0 : strlen($msg),
- ($type=='e' || $type=='i') ? $msg : bin2hex($msg)
- );
- }
- }
- /**
- * Show internal log
- *
- * @param string which log to log show, 'raw' or 'xml'
- *
- * @param string format to display: 'html' (default) or 'raw'
- *
- */
- function showLog($log, $format='html')
- {
- echo '<PRE>';
- foreach ($this->log[$log] as $line) {
- switch ($format) {
- case 'raw':
- echo $line . "\n";
- break;
- case 'html':
- default:
- echo htmlEntities($line) . "\n";
- break;
- }
- }
- echo '</PRE>';
- }
- }