1: <?php
2: /**
3: * Magento
4: *
5: * NOTICE OF LICENSE
6: *
7: * This source file is subject to the Open Software License (OSL 3.0)
8: * that is bundled with this package in the file LICENSE.txt.
9: * It is also available through the world-wide-web at this URL:
10: * http://opensource.org/licenses/osl-3.0.php
11: * If you did not receive a copy of the license and are unable to
12: * obtain it through the world-wide-web, please send an email
13: * to license@magentocommerce.com so we can send you a copy immediately.
14: *
15: * DISCLAIMER
16: *
17: * Do not edit or add to this file if you wish to upgrade Magento to newer
18: * versions in the future. If you wish to customize Magento for your
19: * needs please refer to http://www.magentocommerce.com for more information.
20: *
21: * @category Mage
22: * @package Mage_Api2
23: * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24: * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25: */
26:
27: /**
28: * Request content interpreter XML adapter
29: *
30: * @category Mage
31: * @package Mage_Api2
32: * @author Magento Core Team <core@magentocommerce.com>
33: */
34: class Mage_Api2_Model_Request_Interpreter_Xml implements Mage_Api2_Model_Request_Interpreter_Interface
35: {
36: /**
37: * Default name for item of non-associative array
38: */
39: const ARRAY_NON_ASSOC_ITEM_NAME = 'data_item';
40:
41: /**
42: * Load error string.
43: *
44: * Is null if there was no error while loading
45: *
46: * @var string
47: */
48: protected $_loadErrorStr = null;
49:
50: /**
51: * Parse Request body into array of params
52: *
53: * @param string $body Posted content from request
54: * @return array
55: * @throws Exception|Mage_Api2_Exception
56: */
57: public function interpret($body)
58: {
59: if (!is_string($body)) {
60: throw new Exception(sprintf('Invalid data type "%s". String expected.', gettype($body)));
61: }
62: $body = false !== strpos($body, '<?xml') ? $body : '<?xml version="1.0"?>' . PHP_EOL . $body;
63:
64: // disable external entity loading to prevent possible vulnerability
65: libxml_disable_entity_loader(true);
66: set_error_handler(array($this, '_loadErrorHandler')); // Warnings and errors are suppressed
67: $config = simplexml_load_string($body);
68: restore_error_handler();
69: // restore default behavior to make possible to load external entities
70: libxml_disable_entity_loader(false);
71:
72: // Check if there was a error while loading file
73: if ($this->_loadErrorStr !== null) {
74: throw new Mage_Api2_Exception('Decoding error.', Mage_Api2_Model_Server::HTTP_BAD_REQUEST);
75: }
76:
77: $xml = $this->_toArray($config);
78: return $xml;
79: }
80:
81: /**
82: * Returns an associativearray from a SimpleXMLElement.
83: *
84: * @param SimpleXMLElement $xmlObject Convert a SimpleXMLElement into an array
85: * @return array
86: */
87: protected function _toArray(SimpleXMLElement $xmlObject)
88: {
89: $config = array();
90: // Search for parent node values
91: if (count($xmlObject->attributes()) > 0) {
92: foreach ($xmlObject->attributes() as $key => $value) {
93: $value = (string)$value;
94: if (array_key_exists($key, $config)) {
95: if (!is_array($config[$key])) {
96: $config[$key] = array($config[$key]);
97: }
98: $config[$key][] = $value;
99: } else {
100: $config[$key] = $value;
101: }
102: }
103: }
104:
105: // Search for children
106: if (count($xmlObject->children()) > 0) {
107: foreach ($xmlObject->children() as $key => $value) {
108: if (count($value->children()) > 0) {
109: $value = $this->_toArray($value);
110: } else if (count($value->attributes()) > 0) {
111: $attributes = $value->attributes();
112: if (isset($attributes['value'])) {
113: $value = (string)$attributes['value'];
114: } else {
115: $value = $this->_toArray($value);
116: }
117: } else {
118: $value = (string) $value;
119: }
120: if (array_key_exists($key, $config)) {
121: if (!is_array($config[$key]) || !array_key_exists(0, $config[$key])) {
122: $config[$key] = array($config[$key]);
123: }
124: $config[$key][] = $value;
125: } else {
126: if (self::ARRAY_NON_ASSOC_ITEM_NAME != $key) {
127: $config[$key] = $value;
128: } else {
129: $config[] = $value;
130: }
131: }
132: }
133: }
134:
135: return $config;
136: }
137:
138: /**
139: * Handle any errors from load xml
140: *
141: * @param integer $errno
142: * @param string $errstr
143: * @param string $errfile
144: * @param integer $errline
145: */
146: protected function _loadErrorHandler($errno, $errstr, $errfile, $errline)
147: {
148: if ($this->_loadErrorStr === null) {
149: $this->_loadErrorStr = $errstr;
150: } else {
151: $this->_loadErrorStr .= (PHP_EOL . $errstr);
152: }
153: }
154: }
155: