openSRS_ops.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. <?php
  2. namespace DNSManager\opensrs;
  3. // class openSRS_ops extends PEAR {
  4. class openSRS_ops {
  5. var $_OPS_VERSION = '0.9';
  6. var $_OPT = '';
  7. var $_SPACER = ' '; /* indent character */
  8. var $_CRLF = "\n";
  9. var $_MSGTYPE_STD = 'standard';
  10. var $_SESSID;
  11. var $_MSGCNT;
  12. var $CRLF = "\r\n";
  13. var $_data;
  14. var $_pointers;
  15. var $_last_was_data_block;
  16. /**
  17. * Class constructor
  18. * Initialize variables, logs, etc.
  19. * @param array allows for setting various options (right now, just whether
  20. * to use compression or not on the generated XML)
  21. */
  22. function __construct($args=false) {
  23. if (is_array($args)) {
  24. if ($args['option']=='compress') {
  25. $this->_OPT = 'compress';
  26. $this->_SPACER = '';
  27. $this->_CRLF = '';
  28. }
  29. }
  30. $this->_SESSID = getmypid();
  31. $this->_MSGCNT = 0;
  32. }
  33. /**
  34. * Checks a socket for timeout or EOF
  35. * @param int socket handle
  36. * @return boolean true if the socket has timed out or is EOF
  37. */
  38. function socketStatus(&$fh) {
  39. $return = false;
  40. if (is_resource($fh)) {
  41. $temp = socket_get_status($fh);
  42. if ($temp['timed_out']) $return = true;
  43. if ($temp['eof']) $return = true;
  44. unset($temp);
  45. }
  46. return $return;
  47. }
  48. /**
  49. * Accepts an OPS protocol message or an file handle
  50. * an the data into a PHP array
  51. * @param string OPS message
  52. * @return mixed PHP array, or error
  53. */
  54. function decode($in) {
  55. $ops_msg = '';
  56. /* determine if we were passed a string or file handle */
  57. if (is_resource($in)) {
  58. # read the file into a string, then process as usual
  59. while (!feof($in)) {
  60. $ops_msg .= fgets($in, 400);
  61. }
  62. } else {
  63. $ops_msg = $in;
  64. }
  65. return $this->XML2PHP($ops_msg); /* decode and return */
  66. }
  67. /**
  68. * XML Parser that converts an OPS protocol message into a PHP array
  69. * @param string OPS message
  70. * @return mixed PHP array, or error
  71. */
  72. function XML2PHP($msg) {
  73. $this->_data = NULL;
  74. $xp = xml_parser_create();
  75. xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
  76. xml_parser_set_option($xp, XML_OPTION_SKIP_WHITE, true);
  77. xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING, 'ISO-8859-1');
  78. if (!xml_parse_into_struct($xp,$msg,$vals,$index)) {
  79. $error = sprintf('XML error: %s at line %d',
  80. xml_error_string(xml_get_error_code($xp)),
  81. xml_get_current_line_number($xp)
  82. );
  83. xml_parser_free($xp);
  84. trigger_error ("oSRS Error - ". $error, E_USER_WARNING);
  85. die();
  86. }
  87. xml_parser_free($xp);
  88. $temp = $depth = array();
  89. foreach($vals as $value) {
  90. switch ($value['tag']) {
  91. case 'OPS_envelope':
  92. case 'header':
  93. case 'body':
  94. case 'data_block':
  95. break;
  96. case 'version':
  97. case 'msg_id':
  98. case 'msg_type':
  99. $key = '_OPS_' . $value['tag'];
  100. $temp[$key] = $value['value'];
  101. break;
  102. case 'item':
  103. // Not every Item has attributes
  104. if (isSet($value['attributes'])) {
  105. $key = $value['attributes']['key'];
  106. } else {
  107. $key = "";
  108. }
  109. switch ($value['type']) {
  110. case 'open':
  111. array_push($depth, $key);
  112. break;
  113. case 'complete':
  114. array_push($depth, $key);
  115. $p = join('::',$depth);
  116. // enn_change - make sure that $value['value'] is defined
  117. if (isSet($value['value'])){
  118. $temp[$p] = $value['value'];
  119. } else {
  120. $temp[$p] = "";
  121. }
  122. array_pop($depth);
  123. break;
  124. case 'close':
  125. array_pop($depth);
  126. break;
  127. }
  128. break;
  129. case 'dt_assoc':
  130. case 'dt_array':
  131. break;
  132. }
  133. }
  134. foreach ($temp as $key=>$value) {
  135. $levels = explode('::',$key);
  136. $num_levels = count($levels);
  137. if ($num_levels==1) {
  138. $this->_data[$levels[0]] = $value;
  139. } else {
  140. $pointer = &$this->_data;
  141. for ($i=0; $i<$num_levels; $i++) {
  142. if ( !isset( $pointer[$levels[$i]] ) ) {
  143. $pointer[$levels[$i]] = array();
  144. }
  145. $pointer = &$pointer[$levels[$i]];
  146. }
  147. $pointer = $value;
  148. }
  149. }
  150. return ($this->_data);
  151. }
  152. /**
  153. * Converts a PHP array into an OPS message
  154. * @param array PHP array
  155. * @return string OPS XML message
  156. */
  157. function encode($array) {
  158. $this->_MSGCNT++;
  159. $msg_id = $this->_SESSID + $this->_MSGCNT; /* addition removes the leading zero */
  160. $msg_type = $this->_MSGTYPE_STD;
  161. if ($array['protocol']) {
  162. $array['protocol'] = strtoupper($array['protocol']);
  163. }
  164. if ($array['action']) {
  165. $array['action'] = strtoupper($array['action']);
  166. }
  167. if ($array['object']) {
  168. $array['object'] = strtoupper($array['object']);
  169. }
  170. $xml_data_block = $this->PHP2XML($array);
  171. $ops_msg = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>' . $this->_CRLF .
  172. '<!DOCTYPE OPS_envelope SYSTEM "ops.dtd">' . $this->_CRLF .
  173. '<OPS_envelope>' . $this->_CRLF .
  174. $this->_SPACER . '<header>' . $this->_CRLF .
  175. $this->_SPACER . $this->_SPACER . '<version>' . $this->_OPS_VERSION . '</version>' . $this->_CRLF .
  176. $this->_SPACER . $this->_SPACER . '<msg_id>' . $msg_id . '</msg_id>' . $this->_CRLF .
  177. $this->_SPACER . $this->_SPACER . '<msg_type>' . $msg_type . '</msg_type>' . $this->_CRLF .
  178. $this->_SPACER . '</header>' . $this->_CRLF .
  179. $this->_SPACER . '<body>' . $this->_CRLF .
  180. $xml_data_block . $this->_CRLF .
  181. $this->_SPACER . '</body>' . $this->_CRLF .
  182. '</OPS_envelope>';
  183. return $ops_msg;
  184. }
  185. /**
  186. * Converts a PHP array into an OPS data_block tag
  187. * @param array PHP array
  188. * @return string OPS data_block tag
  189. */
  190. function PHP2XML($data) {
  191. return str_repeat($this->_SPACER,2) . '<data_block>' . $this->_convertData($data, 3) . $this->_CRLF . str_repeat($this->_SPACER,2) . '</data_block>';
  192. }
  193. /**
  194. * Recursivly converts PHP data into XML
  195. * @param mixed PHP array or data
  196. * @param int ident level
  197. * @return string XML string
  198. */
  199. function _convertData(&$array, $indent=0) {
  200. $string = '';
  201. $IND = str_repeat($this->_SPACER,$indent);
  202. if (is_array($array)) {
  203. if ($this->_is_assoc($array)) { # HASH REFERENCE
  204. $string .= $this->_CRLF . $IND . '<dt_assoc>';
  205. $end = '</dt_assoc>';
  206. } else { # ARRAY REFERENCE
  207. $string .= $this->_CRLF . $IND . '<dt_array>';
  208. $end = '</dt_array>';
  209. }
  210. foreach ($array as $k=>$v) {
  211. $indent++;
  212. /* don't encode some types of stuff */
  213. if ((gettype($v)=='resource') || (gettype($v)=='user function') || (gettype($v)=='unknown type')) {
  214. continue;
  215. }
  216. $string .= $this->_CRLF . $IND . '<item key="' . $k . '"';
  217. if (gettype($v)=='object' && get_class($v)) {
  218. $string .= ' class="' . get_class($v) . '"';
  219. }
  220. $string .= '>';
  221. if (is_array($v) || is_object($v)) {
  222. $string .= $this->_convertData($v, $indent+1);
  223. $string .= $this->_CRLF . $IND . '</item>';
  224. } else {
  225. $string .= $this->_quoteXMLChars($v) . '</item>';
  226. }
  227. $indent--;
  228. }
  229. $string .= $this->_CRLF . $IND . $end;
  230. } else { # SCALAR
  231. $string .= $this->_CRLF . $IND . '<dt_scalar>' .
  232. $this->_quoteXMLChars($array) . '</dt_scalar>';
  233. }
  234. return $string;
  235. }
  236. /**
  237. * Quotes special XML characters
  238. * @param string string to quote
  239. * @return string quoted string
  240. */
  241. function _quoteXMLChars($string) {
  242. $search = array ('&', '<', '>', "'", '"');
  243. $replace = array ('&amp;', '&lt;', '&gt;', '&apos;', '&quot;');
  244. $string = str_replace($search, $replace, $string);
  245. $string = utf8_encode($string);
  246. return $string;
  247. }
  248. /**
  249. * Determines if an array is associative or not, since PHP
  250. * doesn't really distinguish between the two, but Perl/OPS does
  251. * @param array array to check
  252. * @return boolean true if the array is associative
  253. */
  254. function _is_assoc(&$array){
  255. if (is_array($array)) {
  256. foreach ($array as $k=>$v) {
  257. if (!is_int($k)) return true;
  258. }
  259. }
  260. return false;
  261. }
  262. }