Merge lp:~magentoerpconnect-community/magentoerpconnect/magento-module-with-crm_claim-integration into lp:magentoerpconnect/magento-module-oerp5.0-stable
- magento-module-with-crm_claim-integration
- Merge into magento-module
Status: | Superseded |
---|---|
Proposed branch: | lp:~magentoerpconnect-community/magentoerpconnect/magento-module-with-crm_claim-integration |
Merge into: | lp:magentoerpconnect/magento-module-oerp5.0-stable |
Diff against target: |
7304 lines (+7182/-0) 18 files modified
Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Block/Form.php (+160/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Helper/Data.php (+74/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System/Config/Backend/Links.php (+48/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/controllers/IndexController.php (+360/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/adminhtml.xml (+22/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/config.xml (+117/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/modules/Savoirfairelinux_Claim.xml (+9/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/system.xml (+114/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc.inc (+3776/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc_wrappers.inc (+955/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpcs.inc (+1246/-0) Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/savoirfairelinux_claim.xml (+70/-0) Savoirfairelinux_Claim/app/design/frontend/default/default/layout/savoirfairelinux_claim.xml (+63/-0) Savoirfairelinux_Claim/app/design/frontend/default/default/template/claim/form.phtml (+121/-0) Savoirfairelinux_Claim/app/etc/modules/Savoirfairelinux_Claim.xml (+9/-0) Savoirfairelinux_Claim/app/locale/en_US/Savoirfairelinux_Claim.csv (+10/-0) Savoirfairelinux_Claim/app/locale/fr_FR/Savoirfairelinux_Claim.csv (+10/-0) Savoirfairelinux_Claim/package.xml (+18/-0) |
To merge this branch: | bzr merge lp:~magentoerpconnect-community/magentoerpconnect/magento-module-with-crm_claim-integration |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MagentoERPConnect core editors | Pending | ||
Review via email: mp+119127@code.launchpad.net |
This proposal supersedes a proposal from 2012-08-10.
Commit message
Description of the change
This Magento module enables Magento users to create a claim (crm_claim) in OpenERP from Magento using OpenERP API.
To post a comment you must log in.
- 25. By Joao Alfredo Gama Batista
-
[ADD] Module to allow Magento users to create a claim in OpenERP from Magento
Unmerged revisions
- 25. By Joao Alfredo Gama Batista
-
[ADD] Module to allow Magento users to create a claim in OpenERP from Magento
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'Savoirfairelinux_Claim' | |||
2 | === added directory 'Savoirfairelinux_Claim/app' | |||
3 | === added directory 'Savoirfairelinux_Claim/app/code' | |||
4 | === added directory 'Savoirfairelinux_Claim/app/code/local' | |||
5 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux' | |||
6 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim' | |||
7 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Block' | |||
8 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Block/Form.php' | |||
9 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Block/Form.php 1970-01-01 00:00:00 +0000 | |||
10 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Block/Form.php 2012-08-10 13:37:19 +0000 | |||
11 | @@ -0,0 +1,160 @@ | |||
12 | 1 | <?php | ||
13 | 2 | /** | ||
14 | 3 | * Magento | ||
15 | 4 | * | ||
16 | 5 | * NOTICE OF LICENSE | ||
17 | 6 | * | ||
18 | 7 | * Savoirfairelinux_Claim | ||
19 | 8 | * Copyright (C) 2012 Savoir-faire Linux | ||
20 | 9 | * | ||
21 | 10 | * This program is free software: you can redistribute it and/or modify | ||
22 | 11 | * it under the terms of the GNU General Public License as published by | ||
23 | 12 | * the Free Software Foundation, either version 3 of the License, or | ||
24 | 13 | * (at your option) any later version. | ||
25 | 14 | * | ||
26 | 15 | * This program is distributed in the hope that it will be useful, | ||
27 | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | 18 | * GNU General Public License for more details. | ||
30 | 19 | * | ||
31 | 20 | * You should have received a copy of the GNU General Public License | ||
32 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
33 | 22 | * | ||
34 | 23 | * DISCLAIMER | ||
35 | 24 | * | ||
36 | 25 | * Do not edit or add to this file if you wish to upgrade Magento to newer | ||
37 | 26 | * versions in the future. If you wish to customize Magento for your | ||
38 | 27 | * needs please refer to http://www.magentocommerce.com for more information. | ||
39 | 28 | * | ||
40 | 29 | * @category Savoirfairelinux | ||
41 | 30 | * @package Savoirfairelinux_Claim | ||
42 | 31 | * @copyright Copyright (c) 2012 Savoir-faire Linux. (http://www.savoirfairelinux.com) | ||
43 | 32 | * @license http://www.gnu.org/licenses/gpl.html General Public License (GPLv3) | ||
44 | 33 | */ | ||
45 | 34 | |||
46 | 35 | /** | ||
47 | 36 | * Customer Complains block | ||
48 | 37 | * | ||
49 | 38 | * @category Savoirfairelinux | ||
50 | 39 | * @package Savoirfairelinux_Claim | ||
51 | 40 | * @author Joao Alfredo Gama Batista <joao.gama@savoirfairelinux.com> | ||
52 | 41 | */ | ||
53 | 42 | class Savoirfairelinux_Claim_Block_Form extends Mage_Customer_Block_Account_Dashboard | ||
54 | 43 | { | ||
55 | 44 | |||
56 | 45 | protected $_collection; | ||
57 | 46 | |||
58 | 47 | const XML_PATH_ENABLED = 'claim/claim/enabled'; | ||
59 | 48 | const XML_PATH_OPENERP_URL = 'claim/settings/openerp_url'; | ||
60 | 49 | const XML_PATH_OPENERP_LOGIN = 'claim/settings/openerp_login'; | ||
61 | 50 | const XML_PATH_OPENERP_PASSWORD = 'claim/settings/openerp_password'; | ||
62 | 51 | const XML_PATH_OPENERP_DATABASE = 'claim/settings/openerp_database'; | ||
63 | 52 | const XML_PATH_OPENERP_CLAIM_REF = 'claim/settings/openerp_claim_ref'; | ||
64 | 53 | const XML_PATH_OPENERP_CLAIM_REF_PREFIX = 'claim/settings/openerp_claim_ref_prefix'; | ||
65 | 54 | |||
66 | 55 | /* protected function _construct() */ | ||
67 | 56 | /* { */ | ||
68 | 57 | /* /\* $this->_collection = Mage::getModel('review/review')->getProductCollection(); *\/ */ | ||
69 | 58 | /* /\* $this->_collection *\/ */ | ||
70 | 59 | /* /\* ->addStoreFilter(Mage::app()->getStore()->getId()) *\/ */ | ||
71 | 60 | /* /\* ->addCustomerFilter(Mage::getSingleton('customer/session')->getCustomerId()) *\/ */ | ||
72 | 61 | /* /\* ->setDateOrder(); *\/ */ | ||
73 | 62 | |||
74 | 63 | /* $this->partner_name = Mage::helper('contacts')->getUserName(); */ | ||
75 | 64 | /* $this->partner_email = Mage::helper('contacts')->getUserEmail(); */ | ||
76 | 65 | |||
77 | 66 | /* $this->openerp = new Savoirfairelinux_Claim_Openerpclient */ | ||
78 | 67 | /* (Mage::getStoreConfig(self::XML_PATH_OPENERP_LOGIN), */ | ||
79 | 68 | /* Mage::helper('core')->decrypt(Mage::getStoreConfig(self::XML_PATH_OPENERP_PASSWORD)), */ | ||
80 | 69 | /* Mage::getStoreConfig(self::XML_PATH_OPENERP_DATABASE), */ | ||
81 | 70 | /* Mage::getStoreConfig(self::XML_PATH_OPENERP_URL), */ | ||
82 | 71 | /* Mage::getStoreConfig(self::XML_PATH_OPENERP_CLAIM_REF), */ | ||
83 | 72 | /* Mage::getStoreConfig(self::XML_PATH_OPENERP_CLAIM_REF_PREFIX) */ | ||
84 | 73 | /* ); */ | ||
85 | 74 | /* parent::__construct(); */ | ||
86 | 75 | |||
87 | 76 | /* } */ | ||
88 | 77 | |||
89 | 78 | public function isPartner() | ||
90 | 79 | { | ||
91 | 80 | $this->partner_name = Mage::helper('contacts')->getUserName(); | ||
92 | 81 | $this->partner_email = Mage::helper('contacts')->getUserEmail(); | ||
93 | 82 | |||
94 | 83 | if( $this->openerp->isPartner($this->partner_name, $this->partner_email) ) | ||
95 | 84 | return True; | ||
96 | 85 | else | ||
97 | 86 | return False; | ||
98 | 87 | |||
99 | 88 | } | ||
100 | 89 | |||
101 | 90 | public function isConnected() | ||
102 | 91 | { | ||
103 | 92 | try { | ||
104 | 93 | $this->openerp = new Savoirfairelinux_Claim_Openerpclient | ||
105 | 94 | (Mage::getStoreConfig(self::XML_PATH_OPENERP_LOGIN), | ||
106 | 95 | Mage::helper('core')->decrypt(Mage::getStoreConfig(self::XML_PATH_OPENERP_PASSWORD)), | ||
107 | 96 | Mage::getStoreConfig(self::XML_PATH_OPENERP_DATABASE), | ||
108 | 97 | Mage::getStoreConfig(self::XML_PATH_OPENERP_URL), | ||
109 | 98 | Mage::getStoreConfig(self::XML_PATH_OPENERP_CLAIM_REF), | ||
110 | 99 | Mage::getStoreConfig(self::XML_PATH_OPENERP_CLAIM_REF_PREFIX)); | ||
111 | 100 | |||
112 | 101 | } catch (Exception $e) { | ||
113 | 102 | return False; | ||
114 | 103 | } | ||
115 | 104 | |||
116 | 105 | return True; | ||
117 | 106 | } | ||
118 | 107 | |||
119 | 108 | public function count() | ||
120 | 109 | { | ||
121 | 110 | return $this->_collection->getSize(); | ||
122 | 111 | } | ||
123 | 112 | |||
124 | 113 | public function getToolbarHtml() | ||
125 | 114 | { | ||
126 | 115 | return $this->getChildHtml('toolbar'); | ||
127 | 116 | } | ||
128 | 117 | |||
129 | 118 | /* protected function _prepareLayout() */ | ||
130 | 119 | /* { */ | ||
131 | 120 | /* $toolbar = $this->getLayout()->createBlock('page/html_pager', 'customer_review_list.toolbar') */ | ||
132 | 121 | /* ->setCollection($this->_getCollection()); */ | ||
133 | 122 | |||
134 | 123 | /* $this->setChild('toolbar', $toolbar); */ | ||
135 | 124 | /* return parent::_prepareLayout(); */ | ||
136 | 125 | /* } */ | ||
137 | 126 | |||
138 | 127 | protected function _getCollection() | ||
139 | 128 | { | ||
140 | 129 | return $this->_collection; | ||
141 | 130 | } | ||
142 | 131 | |||
143 | 132 | public function getCollection() | ||
144 | 133 | { | ||
145 | 134 | return $this->_getCollection(); | ||
146 | 135 | } | ||
147 | 136 | |||
148 | 137 | public function getReviewLink() | ||
149 | 138 | { | ||
150 | 139 | return Mage::getUrl('review/customer/view/'); | ||
151 | 140 | } | ||
152 | 141 | |||
153 | 142 | public function getProductLink() | ||
154 | 143 | { | ||
155 | 144 | return Mage::getUrl('catalog/product/view/'); | ||
156 | 145 | } | ||
157 | 146 | |||
158 | 147 | public function dateFormat($date) | ||
159 | 148 | { | ||
160 | 149 | return $this->formatDate($date, Mage_Core_Model_Locale::FORMAT_TYPE_SHORT); | ||
161 | 150 | } | ||
162 | 151 | |||
163 | 152 | /* protected function _beforeToHtml() */ | ||
164 | 153 | /* { */ | ||
165 | 154 | /* $this->_getCollection() */ | ||
166 | 155 | /* ->load() */ | ||
167 | 156 | /* ->addReviewSummary(); */ | ||
168 | 157 | /* return parent::_beforeToHtml(); */ | ||
169 | 158 | /* } */ | ||
170 | 159 | |||
171 | 160 | } | ||
172 | 0 | 161 | ||
173 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Helper' | |||
174 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Helper/Data.php' | |||
175 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Helper/Data.php 1970-01-01 00:00:00 +0000 | |||
176 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Helper/Data.php 2012-08-10 13:37:19 +0000 | |||
177 | @@ -0,0 +1,74 @@ | |||
178 | 1 | <?php | ||
179 | 2 | /** | ||
180 | 3 | * Magento | ||
181 | 4 | * | ||
182 | 5 | * NOTICE OF LICENSE | ||
183 | 6 | * | ||
184 | 7 | * Savoirfairelinux_Claim | ||
185 | 8 | * Copyright (C) 2012 Savoir-faire Linux | ||
186 | 9 | * | ||
187 | 10 | * This program is free software: you can redistribute it and/or modify | ||
188 | 11 | * it under the terms of the GNU General Public License as published by | ||
189 | 12 | * the Free Software Foundation, either version 3 of the License, or | ||
190 | 13 | * (at your option) any later version. | ||
191 | 14 | * | ||
192 | 15 | * This program is distributed in the hope that it will be useful, | ||
193 | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
194 | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
195 | 18 | * GNU General Public License for more details. | ||
196 | 19 | * | ||
197 | 20 | * You should have received a copy of the GNU General Public License | ||
198 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
199 | 22 | * | ||
200 | 23 | * DISCLAIMER | ||
201 | 24 | * | ||
202 | 25 | * Do not edit or add to this file if you wish to upgrade Magento to newer | ||
203 | 26 | * versions in the future. If you wish to customize Magento for your | ||
204 | 27 | * needs please refer to http://www.magentocommerce.com for more information. | ||
205 | 28 | * | ||
206 | 29 | * @category Savoirfairelinux | ||
207 | 30 | * @package Savoirfairelinux_Claim | ||
208 | 31 | * @copyright Copyright (c) 2012 Savoir-faire Linux. (http://www.savoirfairelinux.com) | ||
209 | 32 | * @license http://www.gnu.org/licenses/gpl.html General Public License (GPLv3) | ||
210 | 33 | */ | ||
211 | 34 | |||
212 | 35 | /** | ||
213 | 36 | * Default claim helper | ||
214 | 37 | * | ||
215 | 38 | * @author Joao Alfredo Gama Batista <joao.gama@savoirfairelinux.com> | ||
216 | 39 | */ | ||
217 | 40 | class Savoirfairelinux_Claim_Helper_Data extends Mage_Core_Helper_Abstract | ||
218 | 41 | { | ||
219 | 42 | |||
220 | 43 | const XML_PATH_ENABLED = 'claim/claim/enabled'; | ||
221 | 44 | |||
222 | 45 | public function getOrdersHtmlSelect() | ||
223 | 46 | { | ||
224 | 47 | if (Mage::getSingleton('customer/session')->isLoggedIn()) { | ||
225 | 48 | $options = array(); | ||
226 | 49 | |||
227 | 50 | $orders = Mage::getResourceModel('sales/order_collection') | ||
228 | 51 | ->addFieldToSelect('*') | ||
229 | 52 | ->addFieldToFilter('customer_id', Mage::getSingleton('customer/session')->getCustomer()->getId()) | ||
230 | 53 | ->addFieldToFilter('state', array('in' => Mage::getSingleton('sales/order_config')->getVisibleOnFrontStates())) | ||
231 | 54 | ->setOrder('created_at', 'desc') | ||
232 | 55 | ; | ||
233 | 56 | |||
234 | 57 | foreach ($orders as $order) { | ||
235 | 58 | $options[] = array('value' => $order->getRealOrderId(), | ||
236 | 59 | 'label' => $order->getRealOrderId()); | ||
237 | 60 | } | ||
238 | 61 | $select = $this->getLayout()->createBlock('core/html_select') | ||
239 | 62 | ->setName('order') | ||
240 | 63 | ->setId('order') | ||
241 | 64 | ->setTitle(Mage::helper('claim')->__('Order')) | ||
242 | 65 | ->setClass('validate-select') | ||
243 | 66 | ->setValue() | ||
244 | 67 | ->setOptions($options); | ||
245 | 68 | |||
246 | 69 | return $select->getHtml(); | ||
247 | 70 | } | ||
248 | 71 | return ''; | ||
249 | 72 | } | ||
250 | 73 | |||
251 | 74 | } | ||
252 | 0 | 75 | ||
253 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model' | |||
254 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System' | |||
255 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System/Config' | |||
256 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System/Config/Backend' | |||
257 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System/Config/Backend/Links.php' | |||
258 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System/Config/Backend/Links.php 1970-01-01 00:00:00 +0000 | |||
259 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/Model/System/Config/Backend/Links.php 2012-08-10 13:37:19 +0000 | |||
260 | @@ -0,0 +1,48 @@ | |||
261 | 1 | <?php | ||
262 | 2 | /** | ||
263 | 3 | * Magento | ||
264 | 4 | * | ||
265 | 5 | * NOTICE OF LICENSE | ||
266 | 6 | * | ||
267 | 7 | * Savoirfairelinux_Claim | ||
268 | 8 | * Copyright (C) 2012 Savoir-faire Linux | ||
269 | 9 | * | ||
270 | 10 | * This program is free software: you can redistribute it and/or modify | ||
271 | 11 | * it under the terms of the GNU General Public License as published by | ||
272 | 12 | * the Free Software Foundation, either version 3 of the License, or | ||
273 | 13 | * (at your option) any later version. | ||
274 | 14 | * | ||
275 | 15 | * This program is distributed in the hope that it will be useful, | ||
276 | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
277 | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
278 | 18 | * GNU General Public License for more details. | ||
279 | 19 | * | ||
280 | 20 | * You should have received a copy of the GNU General Public License | ||
281 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
282 | 22 | * | ||
283 | 23 | * DISCLAIMER | ||
284 | 24 | * | ||
285 | 25 | * Do not edit or add to this file if you wish to upgrade Magento to newer | ||
286 | 26 | * versions in the future. If you wish to customize Magento for your | ||
287 | 27 | * needs please refer to http://www.magentocommerce.com for more information. | ||
288 | 28 | * | ||
289 | 29 | * @category Savoirfairelinux | ||
290 | 30 | * @package Savoirfairelinux_Claim | ||
291 | 31 | * @copyright Copyright (c) 2012 Savoir-faire Linux. (http://www.savoirfairelinux.com) | ||
292 | 32 | * @license http://www.gnu.org/licenses/gpl.html General Public License (GPLv3) | ||
293 | 33 | */ | ||
294 | 34 | |||
295 | 35 | /** | ||
296 | 36 | * Cache cleaner backend model | ||
297 | 37 | * | ||
298 | 38 | */ | ||
299 | 39 | class Savoirfairelinux_Claim_Model_System_Config_Backend_Links extends Mage_Adminhtml_Model_System_Config_Backend_Cache | ||
300 | 40 | { | ||
301 | 41 | /** | ||
302 | 42 | * Cache tags to clean | ||
303 | 43 | * | ||
304 | 44 | * @var array | ||
305 | 45 | */ | ||
306 | 46 | protected $_cacheTags = array(Mage_Core_Model_Store::CACHE_TAG, Mage_Cms_Model_Block::CACHE_TAG); | ||
307 | 47 | |||
308 | 48 | } | ||
309 | 0 | 49 | ||
310 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/controllers' | |||
311 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/controllers/IndexController.php' | |||
312 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/controllers/IndexController.php 1970-01-01 00:00:00 +0000 | |||
313 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/controllers/IndexController.php 2012-08-10 13:37:19 +0000 | |||
314 | @@ -0,0 +1,360 @@ | |||
315 | 1 | <?php | ||
316 | 2 | /** | ||
317 | 3 | * Magento | ||
318 | 4 | * | ||
319 | 5 | * NOTICE OF LICENSE | ||
320 | 6 | * | ||
321 | 7 | * Savoirfairelinux_Claim | ||
322 | 8 | * Copyright (C) 2012 Savoir-faire Linux | ||
323 | 9 | * | ||
324 | 10 | * This program is free software: you can redistribute it and/or modify | ||
325 | 11 | * it under the terms of the GNU General Public License as published by | ||
326 | 12 | * the Free Software Foundation, either version 3 of the License, or | ||
327 | 13 | * (at your option) any later version. | ||
328 | 14 | * | ||
329 | 15 | * This program is distributed in the hope that it will be useful, | ||
330 | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
331 | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
332 | 18 | * GNU General Public License for more details. | ||
333 | 19 | * | ||
334 | 20 | * You should have received a copy of the GNU General Public License | ||
335 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
336 | 22 | * | ||
337 | 23 | * DISCLAIMER | ||
338 | 24 | * | ||
339 | 25 | * Do not edit or add to this file if you wish to upgrade Magento to newer | ||
340 | 26 | * versions in the future. If you wish to customize Magento for your | ||
341 | 27 | * needs please refer to http://www.magentocommerce.com for more information. | ||
342 | 28 | * | ||
343 | 29 | * @category Savoirfairelinux | ||
344 | 30 | * @package Savoirfairelinux_Claim | ||
345 | 31 | * @copyright Copyright (c) 2012 Savoir-faire Linux. (http://www.savoirfairelinux.com) | ||
346 | 32 | * @license http://www.gnu.org/licenses/gpl.html General Public License (GPLv3) | ||
347 | 33 | */ | ||
348 | 34 | |||
349 | 35 | /** | ||
350 | 36 | * Claim index controller | ||
351 | 37 | * | ||
352 | 38 | * @category Savoirfairelinux | ||
353 | 39 | * @package Savoirfairelinux_Claim | ||
354 | 40 | * @author Joao Alfredo Gama Batista <joao.gama@savoirfairelinux.com> | ||
355 | 41 | */ | ||
356 | 42 | |||
357 | 43 | class Savoirfairelinux_Claim_IndexController extends Mage_Core_Controller_Front_Action | ||
358 | 44 | { | ||
359 | 45 | |||
360 | 46 | const XML_PATH_ENABLED = 'claim/claim/enabled'; | ||
361 | 47 | const XML_PATH_OPENERP_URL = 'claim/settings/openerp_url'; | ||
362 | 48 | const XML_PATH_OPENERP_LOGIN = 'claim/settings/openerp_login'; | ||
363 | 49 | const XML_PATH_OPENERP_PASSWORD = 'claim/settings/openerp_password'; | ||
364 | 50 | const XML_PATH_OPENERP_DATABASE = 'claim/settings/openerp_database'; | ||
365 | 51 | const XML_PATH_OPENERP_CLAIM_REF = 'claim/settings/openerp_claim_ref'; | ||
366 | 52 | const XML_PATH_OPENERP_CLAIM_REF_PREFIX = 'claim/settings/openerp_claim_ref_prefix'; | ||
367 | 53 | |||
368 | 54 | public function preDispatch() | ||
369 | 55 | { | ||
370 | 56 | parent::preDispatch(); | ||
371 | 57 | $translate = Mage::getSingleton('core/translate'); | ||
372 | 58 | |||
373 | 59 | if( !Mage::getStoreConfigFlag(self::XML_PATH_ENABLED) ) { | ||
374 | 60 | $this->norouteAction(); | ||
375 | 61 | } | ||
376 | 62 | |||
377 | 63 | if( !Mage::getSingleton('customer/session')->authenticate($this) ) { | ||
378 | 64 | $this->setFlag('', self::FLAG_NO_DISPATCH, true); | ||
379 | 65 | } | ||
380 | 66 | |||
381 | 67 | $this->partner_name = Mage::helper('contacts')->getUserName(); | ||
382 | 68 | |||
383 | 69 | $this->partner_email = Mage::helper('contacts')->getUserEmail(); | ||
384 | 70 | |||
385 | 71 | return; | ||
386 | 72 | } | ||
387 | 73 | |||
388 | 74 | public function indexAction() | ||
389 | 75 | { | ||
390 | 76 | $this->loadLayout(); | ||
391 | 77 | |||
392 | 78 | $this->getLayout()->getBlock('claimForm') | ||
393 | 79 | ->setFormAction( Mage::getUrl('*/*/post') ) | ||
394 | 80 | ->setRefererUrl($this->_getRefererUrl()); | ||
395 | 81 | |||
396 | 82 | if ($navigationBlock = $this->getLayout()->getBlock('customer_account_navigation')) { | ||
397 | 83 | $navigationBlock->setActive('claim'); | ||
398 | 84 | } | ||
399 | 85 | |||
400 | 86 | $this->_initLayoutMessages('customer/session'); | ||
401 | 87 | $this->_initLayoutMessages('catalog/session'); | ||
402 | 88 | $this->renderLayout(); | ||
403 | 89 | } | ||
404 | 90 | |||
405 | 91 | public function postAction() | ||
406 | 92 | { | ||
407 | 93 | |||
408 | 94 | $post = $this->getRequest()->getPost(); | ||
409 | 95 | if ( $post ) { | ||
410 | 96 | $translate = Mage::getSingleton('core/translate'); | ||
411 | 97 | /* @var $translate Mage_Core_Model_Translate */ | ||
412 | 98 | $translate->setTranslateInline(false); | ||
413 | 99 | try { | ||
414 | 100 | $postObject = new Varien_Object(); | ||
415 | 101 | $postObject->setData($post); | ||
416 | 102 | |||
417 | 103 | $error = false; | ||
418 | 104 | |||
419 | 105 | If (!Zend_Validate::is(trim($post['subject']) , 'NotEmpty')) { | ||
420 | 106 | $error = true; | ||
421 | 107 | } | ||
422 | 108 | |||
423 | 109 | if ($error) { | ||
424 | 110 | throw new Exception(); | ||
425 | 111 | } | ||
426 | 112 | |||
427 | 113 | $this->openerp = new Savoirfairelinux_Claim_Openerpclient | ||
428 | 114 | (Mage::getStoreConfig(self::XML_PATH_OPENERP_LOGIN), | ||
429 | 115 | Mage::helper('core')->decrypt(Mage::getStoreConfig(self::XML_PATH_OPENERP_PASSWORD)), | ||
430 | 116 | Mage::getStoreConfig(self::XML_PATH_OPENERP_DATABASE), | ||
431 | 117 | Mage::getStoreConfig(self::XML_PATH_OPENERP_URL), | ||
432 | 118 | Mage::getStoreConfig(self::XML_PATH_OPENERP_CLAIM_REF), | ||
433 | 119 | Mage::getStoreConfig(self::XML_PATH_OPENERP_CLAIM_REF_PREFIX) | ||
434 | 120 | ); | ||
435 | 121 | |||
436 | 122 | /* $openerp->connect(); */ | ||
437 | 123 | $partner_id = $this->openerp->getPartnerId($this->partner_name, | ||
438 | 124 | $this->partner_email); | ||
439 | 125 | $partner_contact_id = $this->openerp->getPartnerContactId($partner_id); | ||
440 | 126 | $order_id = $this->openerp->getOrderId(trim($post['order'])); | ||
441 | 127 | $this->openerp->createClaim($partner_id, | ||
442 | 128 | $partner_contact_id, | ||
443 | 129 | $order_id, | ||
444 | 130 | trim($post['subject']), | ||
445 | 131 | trim($post['claim'])); | ||
446 | 132 | |||
447 | 133 | |||
448 | 134 | $translate->setTranslateInline(true); | ||
449 | 135 | |||
450 | 136 | Mage::getSingleton('customer/session')->addSuccess(Mage::helper('claim')->__('Your complaint was submitted and will be responded to as soon as possible. Thank you for contacting us.')); | ||
451 | 137 | $this->_redirect('*/*/'); | ||
452 | 138 | |||
453 | 139 | return; | ||
454 | 140 | } catch (Exception $e) { | ||
455 | 141 | $translate->setTranslateInline(true); | ||
456 | 142 | |||
457 | 143 | Mage::getSingleton('customer/session')->addError(Mage::helper('claim')->__('Unable to submit your complaint. Please, try again later.')); | ||
458 | 144 | $this->_redirect('*/*/'); | ||
459 | 145 | return; | ||
460 | 146 | } | ||
461 | 147 | |||
462 | 148 | } else { | ||
463 | 149 | $this->_redirect('*/*/'); | ||
464 | 150 | } | ||
465 | 151 | } | ||
466 | 152 | |||
467 | 153 | } | ||
468 | 154 | |||
469 | 155 | class Savoirfairelinux_Claim_Openerpclient | ||
470 | 156 | { | ||
471 | 157 | |||
472 | 158 | function __construct($usr, $pass, $db, $server, $claim_ref, $claim_ref_prefix) | ||
473 | 159 | { | ||
474 | 160 | |||
475 | 161 | $ExternalLibPath=Mage::getModuleDir('', 'Savoirfairelinux_Claim').DS.'lib'.DS.'xmlrpc.inc'; | ||
476 | 162 | require_once ($ExternalLibPath); | ||
477 | 163 | |||
478 | 164 | $this->user = $usr; | ||
479 | 165 | $this->password = $pass; | ||
480 | 166 | $this->database = $db; | ||
481 | 167 | $this->services = $server; | ||
482 | 168 | $this->claim_ref = $claim_ref; | ||
483 | 169 | $this->claim_ref_prefix = $claim_ref_prefix; | ||
484 | 170 | |||
485 | 171 | $this->client = new xmlrpc_client($this->services.'common'); | ||
486 | 172 | |||
487 | 173 | $this->msg = new xmlrpcmsg('login'); | ||
488 | 174 | $this->msg->addParam(new xmlrpcval($this->database, "string")); | ||
489 | 175 | $this->msg->addParam(new xmlrpcval($this->user, "string")); | ||
490 | 176 | $this->msg->addParam(new xmlrpcval($this->password, "string")); | ||
491 | 177 | |||
492 | 178 | $this->res = &$this->client->send($this->msg); | ||
493 | 179 | |||
494 | 180 | if(!$this->res->faultCode()){ | ||
495 | 181 | $this->userid = $this->res->value()->scalarval(); | ||
496 | 182 | } | ||
497 | 183 | else { | ||
498 | 184 | Mage::log("Unable to login ".$this->res->faultString()); | ||
499 | 185 | throw new Exception(); | ||
500 | 186 | exit; | ||
501 | 187 | } | ||
502 | 188 | } | ||
503 | 189 | |||
504 | 190 | public function getPartnerId($partner, $email) | ||
505 | 191 | { | ||
506 | 192 | Mage::log('getPartnerId: '.$partner); | ||
507 | 193 | |||
508 | 194 | $key = array(new xmlrpcval(array(new xmlrpcval("name" , "string"), | ||
509 | 195 | new xmlrpcval("=","string"), | ||
510 | 196 | new xmlrpcval($partner, "string")),"array"), | ||
511 | 197 | ); | ||
512 | 198 | |||
513 | 199 | $ids = $this->search('res.partner', $key); | ||
514 | 200 | if(sizeof($ids) == 0) { | ||
515 | 201 | $id = -1; | ||
516 | 202 | } elseif(sizeof($ids) == 1) { | ||
517 | 203 | $id = $ids[0]->scalarval(); | ||
518 | 204 | } elseif( sizeof($ids) > 1) { | ||
519 | 205 | foreach( $ids as $v ) { | ||
520 | 206 | $m = $this->getPartnerEmail($v); | ||
521 | 207 | if( $m == $email ) | ||
522 | 208 | $id = $v->scalarval(); | ||
523 | 209 | } | ||
524 | 210 | } | ||
525 | 211 | /* return $ids; */ | ||
526 | 212 | Mage::log('getPartnerId: '.$id); | ||
527 | 213 | return $id; | ||
528 | 214 | } | ||
529 | 215 | |||
530 | 216 | public function isPartner($name, $email) | ||
531 | 217 | { | ||
532 | 218 | $partner_id = $this->getPartnerId($name, $email); | ||
533 | 219 | if( $partner_id == -1 ) | ||
534 | 220 | $ret = False; | ||
535 | 221 | else | ||
536 | 222 | $ret = True; | ||
537 | 223 | |||
538 | 224 | return $ret; | ||
539 | 225 | } | ||
540 | 226 | |||
541 | 227 | public function getPartnerContactId($partner_id) | ||
542 | 228 | { | ||
543 | 229 | Mage::log('getPartnerContactId: '.$partner_id); | ||
544 | 230 | |||
545 | 231 | $key = array(new xmlrpcval(array(new xmlrpcval("partner_id" , "string"), | ||
546 | 232 | new xmlrpcval("=","string"), | ||
547 | 233 | new xmlrpcval($partner_id, "int")),"array")); | ||
548 | 234 | |||
549 | 235 | $ids = $this->search('res.partner.address', $key); | ||
550 | 236 | /* return $ids; */ | ||
551 | 237 | Mage::log('getpartnerContactId: '.$ids[0]->scalarval()); | ||
552 | 238 | return $ids[0]->scalarval(); | ||
553 | 239 | } | ||
554 | 240 | |||
555 | 241 | public function getOrderId($order) | ||
556 | 242 | { | ||
557 | 243 | |||
558 | 244 | $key = array(new xmlrpcval(array(new xmlrpcval("name" , "string"), | ||
559 | 245 | new xmlrpcval("=","string"), | ||
560 | 246 | new xmlrpcval($this->claim_ref_prefix.$order, "string")),"array"), | ||
561 | 247 | ); | ||
562 | 248 | |||
563 | 249 | $ids = $this->search($this->claim_ref, $key); | ||
564 | 250 | if( sizeof($ids) > 1 ) { | ||
565 | 251 | Mage::log('Duplicated orders error!!'); | ||
566 | 252 | throw new Exception(); | ||
567 | 253 | } | ||
568 | 254 | |||
569 | 255 | /* return $ids; */ | ||
570 | 256 | Mage::log('Order_id: '.$ids[0]->scalarval()); | ||
571 | 257 | return $ids[0]->scalarval(); | ||
572 | 258 | } | ||
573 | 259 | |||
574 | 260 | public function createClaim($partner, | ||
575 | 261 | $partner_address, | ||
576 | 262 | $order, | ||
577 | 263 | $subject, | ||
578 | 264 | $description) | ||
579 | 265 | { | ||
580 | 266 | $arrayVal = array( | ||
581 | 267 | 'name'=>new xmlrpcval($subject, "string") , | ||
582 | 268 | 'description'=>new xmlrpcval($description, "string"), | ||
583 | 269 | 'partner_id'=>new xmlrpcval($partner, "int"), | ||
584 | 270 | 'partner_address_id'=>new xmlrpcval($partner_address, "int"), | ||
585 | 271 | 'ref'=>new xmlrpcval('sale.order,'.$order, 'string') | ||
586 | 272 | ); | ||
587 | 273 | |||
588 | 274 | $this->client = new xmlrpc_client($this->services."object"); | ||
589 | 275 | |||
590 | 276 | $this->msg = new xmlrpcmsg('execute'); | ||
591 | 277 | $this->msg->addParam(new xmlrpcval($this->database, "string")); | ||
592 | 278 | $this->msg->addParam(new xmlrpcval($this->userid, "int")); | ||
593 | 279 | $this->msg->addParam(new xmlrpcval($this->password, "string")); | ||
594 | 280 | $this->msg->addParam(new xmlrpcval("crm.claim", "string")); | ||
595 | 281 | $this->msg->addParam(new xmlrpcval("create", "string")); | ||
596 | 282 | $this->msg->addParam(new xmlrpcval($arrayVal, "struct")); | ||
597 | 283 | |||
598 | 284 | $this->resp = $this->client->send($this->msg); | ||
599 | 285 | |||
600 | 286 | if ($this->resp->faultCode()) | ||
601 | 287 | Mage::log('Error: '.$this->resp->faultString()); | ||
602 | 288 | else | ||
603 | 289 | Mage::log('Claim '.$this->resp->value()->scalarval().' created !'); | ||
604 | 290 | |||
605 | 291 | } | ||
606 | 292 | |||
607 | 293 | public function getPartnerEmail($partner_id) | ||
608 | 294 | { | ||
609 | 295 | Mage::log('getPartnerEmail: '.$partner_id->scalarval()); | ||
610 | 296 | |||
611 | 297 | $ids = array($partner_id); | ||
612 | 298 | $fields = array(new xmlrpcval('email', 'string')); | ||
613 | 299 | |||
614 | 300 | $ids = $this->read('res.partner', $ids, $fields); | ||
615 | 301 | |||
616 | 302 | $id = $ids[0]->scalarval(); | ||
617 | 303 | Mage::log('getPartnerEmail: '.$id['email']->scalarval()); | ||
618 | 304 | return $id['email']->scalarval(); | ||
619 | 305 | } | ||
620 | 306 | |||
621 | 307 | public function search($relation, $key) | ||
622 | 308 | { | ||
623 | 309 | Mage::log('search: '.$relation); | ||
624 | 310 | $this->client = new xmlrpc_client($this->services.'object'); | ||
625 | 311 | |||
626 | 312 | $this->msg = new xmlrpcmsg('execute'); | ||
627 | 313 | $this->msg->addParam(new xmlrpcval($this->database, "string")); | ||
628 | 314 | $this->msg->addParam(new xmlrpcval($this->userid, "int")); | ||
629 | 315 | $this->msg->addParam(new xmlrpcval($this->password, "string")); | ||
630 | 316 | $this->msg->addParam(new xmlrpcval($relation, "string")); | ||
631 | 317 | $this->msg->addParam(new xmlrpcval("search", "string")); | ||
632 | 318 | $this->msg->addParam(new xmlrpcval($key, "array")); | ||
633 | 319 | |||
634 | 320 | $this->resp = $this->client->send($this->msg); | ||
635 | 321 | |||
636 | 322 | if ($this->resp->faultCode()) { | ||
637 | 323 | Mage::log('Search error: '.$this->resp->faultString()); | ||
638 | 324 | $id = ''; | ||
639 | 325 | } else { | ||
640 | 326 | Mage::log('Search '.$relation.' succeded !'); | ||
641 | 327 | $id = $this->resp->value()->scalarval(); | ||
642 | 328 | } | ||
643 | 329 | |||
644 | 330 | return $id; | ||
645 | 331 | } | ||
646 | 332 | |||
647 | 333 | public function read($relation, $ids, $fields) | ||
648 | 334 | { | ||
649 | 335 | Mage::log('read: '.$relation); | ||
650 | 336 | $this->client = new xmlrpc_client($this->services.'object'); | ||
651 | 337 | |||
652 | 338 | $this->msg = new xmlrpcmsg('execute'); | ||
653 | 339 | $this->msg->addParam(new xmlrpcval($this->database, "string")); | ||
654 | 340 | $this->msg->addParam(new xmlrpcval($this->userid, "int")); | ||
655 | 341 | $this->msg->addParam(new xmlrpcval($this->password, "string")); | ||
656 | 342 | $this->msg->addParam(new xmlrpcval($relation, "string")); | ||
657 | 343 | $this->msg->addParam(new xmlrpcval("read", "string")); | ||
658 | 344 | $this->msg->addParam(new xmlrpcval($ids, "array")); | ||
659 | 345 | $this->msg->addParam(new xmlrpcval($fields, "array")); | ||
660 | 346 | |||
661 | 347 | $this->resp = $this->client->send($this->msg); | ||
662 | 348 | |||
663 | 349 | if ($this->resp->faultCode()) { | ||
664 | 350 | Mage::log('Read error: '.$this->resp->faultString()); | ||
665 | 351 | $id = ''; | ||
666 | 352 | } else { | ||
667 | 353 | Mage::log('Read '.$relation.' succeded !'); | ||
668 | 354 | $id = $this->resp->value()->scalarval(); | ||
669 | 355 | } | ||
670 | 356 | |||
671 | 357 | return $id; | ||
672 | 358 | } | ||
673 | 359 | |||
674 | 360 | } | ||
675 | 0 | 361 | ||
676 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc' | |||
677 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/adminhtml.xml' | |||
678 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/adminhtml.xml 1970-01-01 00:00:00 +0000 | |||
679 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/adminhtml.xml 2012-08-10 13:37:19 +0000 | |||
680 | @@ -0,0 +1,22 @@ | |||
681 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
682 | 2 | <config> | ||
683 | 3 | <acl> | ||
684 | 4 | <resources> | ||
685 | 5 | <admin> | ||
686 | 6 | <children> | ||
687 | 7 | <system> | ||
688 | 8 | <children> | ||
689 | 9 | <config> | ||
690 | 10 | <children> | ||
691 | 11 | <claim translate="title" module="claim"> | ||
692 | 12 | <title>Complaints Settings</title> | ||
693 | 13 | </claim> | ||
694 | 14 | </children> | ||
695 | 15 | </config> | ||
696 | 16 | </children> | ||
697 | 17 | </system> | ||
698 | 18 | </children> | ||
699 | 19 | </admin> | ||
700 | 20 | </resources> | ||
701 | 21 | </acl> | ||
702 | 22 | </config> | ||
703 | 0 | \ No newline at end of file | 23 | \ No newline at end of file |
704 | 1 | 24 | ||
705 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/config.xml' | |||
706 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/config.xml 1970-01-01 00:00:00 +0000 | |||
707 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/config.xml 2012-08-10 13:37:19 +0000 | |||
708 | @@ -0,0 +1,117 @@ | |||
709 | 1 | <?xml version="1.0"?> | ||
710 | 2 | <!-- | ||
711 | 3 | /** | ||
712 | 4 | * Magento | ||
713 | 5 | * | ||
714 | 6 | * NOTICE OF LICENSE | ||
715 | 7 | * | ||
716 | 8 | * Savoirfairelinux_Claim | ||
717 | 9 | * Copyright (C) 2012 Savoir-faire Linux | ||
718 | 10 | * | ||
719 | 11 | * This program is free software: you can redistribute it and/or modify | ||
720 | 12 | * it under the terms of the GNU General Public License as published by | ||
721 | 13 | * the Free Software Foundation, either version 3 of the License, or | ||
722 | 14 | * (at your option) any later version. | ||
723 | 15 | * | ||
724 | 16 | * This program is distributed in the hope that it will be useful, | ||
725 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
726 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
727 | 19 | * GNU General Public License for more details. | ||
728 | 20 | * | ||
729 | 21 | * You should have received a copy of the GNU General Public License | ||
730 | 22 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
731 | 23 | * | ||
732 | 24 | * DISCLAIMER | ||
733 | 25 | * | ||
734 | 26 | * Do not edit or add to this file if you wish to upgrade Magento to newer | ||
735 | 27 | * versions in the future. If you wish to customize Magento for your | ||
736 | 28 | * needs please refer to http://www.magentocommerce.com for more information. | ||
737 | 29 | * | ||
738 | 30 | * @category Savoirfairelinux | ||
739 | 31 | * @package Savoirfairelinux_Claim | ||
740 | 32 | * @copyright Copyright (c) 2012 Savoir-faire Linux (http://www.savoirfairelinux.com) | ||
741 | 33 | * @license http://www.gnu.org/licenses/gpl.html General Public License (GPLv3) | ||
742 | 34 | */ | ||
743 | 35 | --> | ||
744 | 36 | <config> | ||
745 | 37 | <modules> | ||
746 | 38 | <Savoirfairelinux_Claim> | ||
747 | 39 | <version>0.1.1</version> | ||
748 | 40 | </Savoirfairelinux_Claim> | ||
749 | 41 | </modules> | ||
750 | 42 | <global> | ||
751 | 43 | <!-- <resources> --> | ||
752 | 44 | <!-- <claim_setup> --> | ||
753 | 45 | <!-- <setup> --> | ||
754 | 46 | <!-- <module>Savoirfairelinux_Claim</module> --> | ||
755 | 47 | <!-- </setup> --> | ||
756 | 48 | <!-- </claim_setup> --> | ||
757 | 49 | <!-- </resources> --> | ||
758 | 50 | <helpers> | ||
759 | 51 | <claim> | ||
760 | 52 | <class>Savoirfairelinux_Claim_Helper</class> | ||
761 | 53 | </claim> | ||
762 | 54 | </helpers> | ||
763 | 55 | |||
764 | 56 | <blocks> | ||
765 | 57 | <claim> | ||
766 | 58 | <class>Savoirfairelinux_Claim_Block</class> | ||
767 | 59 | </claim> | ||
768 | 60 | </blocks> | ||
769 | 61 | |||
770 | 62 | </global> | ||
771 | 63 | |||
772 | 64 | <adminhtml> | ||
773 | 65 | <translate> | ||
774 | 66 | <modules> | ||
775 | 67 | <Savoirfairelinux_Claim> | ||
776 | 68 | <files> | ||
777 | 69 | <default>Savoirfairelinux_Claim.csv</default> | ||
778 | 70 | </files> | ||
779 | 71 | </Savoirfairelinux_Claim> | ||
780 | 72 | </modules> | ||
781 | 73 | </translate> | ||
782 | 74 | </adminhtml> | ||
783 | 75 | <frontend> | ||
784 | 76 | <routers> | ||
785 | 77 | <claim> | ||
786 | 78 | <use>standard</use> | ||
787 | 79 | <args> | ||
788 | 80 | <module>Savoirfairelinux_Claim</module> | ||
789 | 81 | <frontName>claim</frontName> | ||
790 | 82 | </args> | ||
791 | 83 | </claim> | ||
792 | 84 | </routers> | ||
793 | 85 | <translate> | ||
794 | 86 | <modules> | ||
795 | 87 | <Savoirfairelinux_Claim> | ||
796 | 88 | <files> | ||
797 | 89 | <default>Savoirfairelinux_Claim.csv</default> | ||
798 | 90 | </files> | ||
799 | 91 | </Savoirfairelinux_Claim> | ||
800 | 92 | </modules> | ||
801 | 93 | </translate> | ||
802 | 94 | <layout> | ||
803 | 95 | <updates> | ||
804 | 96 | <claim> | ||
805 | 97 | <file>savoirfairelinux_claim.xml</file> | ||
806 | 98 | </claim> | ||
807 | 99 | </updates> | ||
808 | 100 | </layout> | ||
809 | 101 | </frontend> | ||
810 | 102 | <default> | ||
811 | 103 | <claim> | ||
812 | 104 | <claim> | ||
813 | 105 | <enabled>1</enabled> | ||
814 | 106 | </claim> | ||
815 | 107 | <settings> | ||
816 | 108 | <openerp_url>http://localhost:8069/xmlrpc/</openerp_url> | ||
817 | 109 | <openerp_database>test</openerp_database> | ||
818 | 110 | <openerp_login>admin</openerp_login> | ||
819 | 111 | <openerp_password>admin123</openerp_password> | ||
820 | 112 | <openerp_claim_ref>sale.order</openerp_claim_ref> | ||
821 | 113 | <openerp_claim_ref_prefix>mag_</openerp_claim_ref_prefix> | ||
822 | 114 | </settings> | ||
823 | 115 | </claim> | ||
824 | 116 | </default> | ||
825 | 117 | </config> | ||
826 | 0 | 118 | ||
827 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/modules' | |||
828 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/modules/Savoirfairelinux_Claim.xml' | |||
829 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/modules/Savoirfairelinux_Claim.xml 1970-01-01 00:00:00 +0000 | |||
830 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/modules/Savoirfairelinux_Claim.xml 2012-08-10 13:37:19 +0000 | |||
831 | @@ -0,0 +1,9 @@ | |||
832 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
833 | 2 | <config> | ||
834 | 3 | <modules> | ||
835 | 4 | <Savoirfairelinux_Claim> | ||
836 | 5 | <active>true</active> | ||
837 | 6 | <codePool>local</codePool> | ||
838 | 7 | </Savoirfairelinux_Claim> | ||
839 | 8 | </modules> | ||
840 | 9 | </config> | ||
841 | 0 | 10 | ||
842 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/system.xml' | |||
843 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/system.xml 1970-01-01 00:00:00 +0000 | |||
844 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/etc/system.xml 2012-08-10 13:37:19 +0000 | |||
845 | @@ -0,0 +1,114 @@ | |||
846 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
847 | 2 | <config> | ||
848 | 3 | <sections> | ||
849 | 4 | <claim translate="label" module="claim"> | ||
850 | 5 | <label>Complaints</label> | ||
851 | 6 | <tab>customer</tab> | ||
852 | 7 | <frontend_type>text</frontend_type> | ||
853 | 8 | <sort_order>990</sort_order> | ||
854 | 9 | <show_in_default>1</show_in_default> | ||
855 | 10 | <show_in_website>1</show_in_website> | ||
856 | 11 | <show_in_store>1</show_in_store> | ||
857 | 12 | <groups> | ||
858 | 13 | <claim translate="label"> | ||
859 | 14 | <label>Claim</label> | ||
860 | 15 | <frontend_type>text</frontend_type> | ||
861 | 16 | <sort_order>20</sort_order> | ||
862 | 17 | <show_in_default>1</show_in_default> | ||
863 | 18 | <show_in_website>1</show_in_website> | ||
864 | 19 | <show_in_store>1</show_in_store> | ||
865 | 20 | <fields> | ||
866 | 21 | <enabled translate="label"> | ||
867 | 22 | <label>Enabled</label> | ||
868 | 23 | <frontend_type>select</frontend_type> | ||
869 | 24 | <source_model>adminhtml/system_config_source_yesno</source_model> | ||
870 | 25 | <!-- <backend_model>claim/system_config_backend_links</backend_model> --> | ||
871 | 26 | <sort_order>4</sort_order> | ||
872 | 27 | <show_in_default>1</show_in_default> | ||
873 | 28 | <show_in_website>1</show_in_website> | ||
874 | 29 | <show_in_store>1</show_in_store> | ||
875 | 30 | </enabled> | ||
876 | 31 | |||
877 | 32 | <!-- <enabled translate="label"> --> | ||
878 | 33 | <!-- <label>Enabled</label> --> | ||
879 | 34 | <!-- <frontend_type>select</frontend_type> --> | ||
880 | 35 | <!-- <source_model>adminhtml/system_config_source_yesno</source_model> --> | ||
881 | 36 | <!-- <backend_model>savoirfairelinux_claim/system_config_backend_links</backend_model> --> | ||
882 | 37 | <!-- <sort_order>1</sort_order> --> | ||
883 | 38 | <!-- <show_in_default>1</show_in_default> --> | ||
884 | 39 | <!-- <show_in_website>1</show_in_website> --> | ||
885 | 40 | <!-- <show_in_store>1</show_in_store> --> | ||
886 | 41 | <!-- </enabled> --> | ||
887 | 42 | </fields> | ||
888 | 43 | </claim> | ||
889 | 44 | <settings translate="label"> | ||
890 | 45 | <label>OpenERP Settings</label> | ||
891 | 46 | <frontend_type>text</frontend_type> | ||
892 | 47 | <sort_order>20</sort_order> | ||
893 | 48 | <show_in_default>1</show_in_default> | ||
894 | 49 | <show_in_website>1</show_in_website> | ||
895 | 50 | <show_in_store>1</show_in_store> | ||
896 | 51 | <fields> | ||
897 | 52 | <openerp_url translate="label,comment"> | ||
898 | 53 | <label>OpenERP server URL</label> | ||
899 | 54 | <comment><![CDATA[]]></comment> | ||
900 | 55 | <frontend_type>text</frontend_type> | ||
901 | 56 | <sort_order>1</sort_order> | ||
902 | 57 | <show_in_default>1</show_in_default> | ||
903 | 58 | <show_in_website>1</show_in_website> | ||
904 | 59 | <show_in_store>1</show_in_store> | ||
905 | 60 | </openerp_url> | ||
906 | 61 | <openerp_database translate="label,comment"> | ||
907 | 62 | <label>OpenERP database name</label> | ||
908 | 63 | <comment><![CDATA[]]></comment> | ||
909 | 64 | <frontend_type>text</frontend_type> | ||
910 | 65 | <sort_order>1</sort_order> | ||
911 | 66 | <show_in_default>1</show_in_default> | ||
912 | 67 | <show_in_website>1</show_in_website> | ||
913 | 68 | <show_in_store>1</show_in_store> | ||
914 | 69 | </openerp_database> | ||
915 | 70 | |||
916 | 71 | <openerp_login translate="label"> | ||
917 | 72 | <label>OpenERP login</label> | ||
918 | 73 | <frontend_type>text</frontend_type> | ||
919 | 74 | <sort_order>2</sort_order> | ||
920 | 75 | <show_in_default>1</show_in_default> | ||
921 | 76 | <show_in_website>1</show_in_website> | ||
922 | 77 | <show_in_store>1</show_in_store> | ||
923 | 78 | </openerp_login> | ||
924 | 79 | <openerp_password translate="label,comment"> | ||
925 | 80 | <label>OpenERP password</label> | ||
926 | 81 | <comment></comment> | ||
927 | 82 | <backend_model>adminhtml/system_config_backend_encrypted</backend_model> | ||
928 | 83 | <frontend_type>obscure</frontend_type> | ||
929 | 84 | <sort_order>3</sort_order> | ||
930 | 85 | <show_in_default>1</show_in_default> | ||
931 | 86 | <show_in_website>1</show_in_website> | ||
932 | 87 | <show_in_store>1</show_in_store> | ||
933 | 88 | </openerp_password> | ||
934 | 89 | <openerp_claim_ref translate="label,comment"> | ||
935 | 90 | <label>OpenERP Reference field entity</label> | ||
936 | 91 | <comment></comment> | ||
937 | 92 | <frontend_type>text</frontend_type> | ||
938 | 93 | <sort_order>4</sort_order> | ||
939 | 94 | <show_in_default>1</show_in_default> | ||
940 | 95 | <show_in_website>1</show_in_website> | ||
941 | 96 | <show_in_store>1</show_in_store> | ||
942 | 97 | </openerp_claim_ref> | ||
943 | 98 | <openerp_claim_ref_prefix translate="label,comment"> | ||
944 | 99 | <label>OpenERP Reference field prefix</label> | ||
945 | 100 | <comment></comment> | ||
946 | 101 | <frontend_type>text</frontend_type> | ||
947 | 102 | <sort_order>5</sort_order> | ||
948 | 103 | <show_in_default>1</show_in_default> | ||
949 | 104 | <show_in_website>1</show_in_website> | ||
950 | 105 | <show_in_store>1</show_in_store> | ||
951 | 106 | </openerp_claim_ref_prefix> | ||
952 | 107 | </fields> | ||
953 | 108 | </settings> | ||
954 | 109 | </groups> | ||
955 | 110 | </claim> | ||
956 | 111 | </sections> | ||
957 | 112 | </config> | ||
958 | 113 | |||
959 | 114 | |||
960 | 0 | \ No newline at end of file | 115 | \ No newline at end of file |
961 | 1 | 116 | ||
962 | === added directory 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib' | |||
963 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc.inc' | |||
964 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc.inc 1970-01-01 00:00:00 +0000 | |||
965 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc.inc 2012-08-10 13:37:19 +0000 | |||
966 | @@ -0,0 +1,3776 @@ | |||
967 | 1 | <?php | ||
968 | 2 | // by Edd Dumbill (C) 1999-2002 | ||
969 | 3 | // <edd@usefulinc.com> | ||
970 | 4 | // $Id: xmlrpc.inc,v 1.174 2009/03/16 19:36:38 ggiunta Exp $ | ||
971 | 5 | |||
972 | 6 | // Copyright (c) 1999,2000,2002 Edd Dumbill. | ||
973 | 7 | // All rights reserved. | ||
974 | 8 | // | ||
975 | 9 | // Redistribution and use in source and binary forms, with or without | ||
976 | 10 | // modification, are permitted provided that the following conditions | ||
977 | 11 | // are met: | ||
978 | 12 | // | ||
979 | 13 | // * Redistributions of source code must retain the above copyright | ||
980 | 14 | // notice, this list of conditions and the following disclaimer. | ||
981 | 15 | // | ||
982 | 16 | // * Redistributions in binary form must reproduce the above | ||
983 | 17 | // copyright notice, this list of conditions and the following | ||
984 | 18 | // disclaimer in the documentation and/or other materials provided | ||
985 | 19 | // with the distribution. | ||
986 | 20 | // | ||
987 | 21 | // * Neither the name of the "XML-RPC for PHP" nor the names of its | ||
988 | 22 | // contributors may be used to endorse or promote products derived | ||
989 | 23 | // from this software without specific prior written permission. | ||
990 | 24 | // | ||
991 | 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
992 | 26 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
993 | 27 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
994 | 28 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
995 | 29 | // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
996 | 30 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
997 | 31 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
998 | 32 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
999 | 33 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
1000 | 34 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
1001 | 35 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
1002 | 36 | // OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1003 | 37 | |||
1004 | 38 | if(!function_exists('xml_parser_create')) | ||
1005 | 39 | { | ||
1006 | 40 | // For PHP 4 onward, XML functionality is always compiled-in on windows: | ||
1007 | 41 | // no more need to dl-open it. It might have been compiled out on *nix... | ||
1008 | 42 | if(strtoupper(substr(PHP_OS, 0, 3) != 'WIN')) | ||
1009 | 43 | { | ||
1010 | 44 | dl('xml.so'); | ||
1011 | 45 | } | ||
1012 | 46 | } | ||
1013 | 47 | |||
1014 | 48 | // G. Giunta 2005/01/29: declare global these variables, | ||
1015 | 49 | // so that xmlrpc.inc will work even if included from within a function | ||
1016 | 50 | // Milosch: 2005/08/07 - explicitly request these via $GLOBALS where used. | ||
1017 | 51 | $GLOBALS['xmlrpcI4']='i4'; | ||
1018 | 52 | $GLOBALS['xmlrpcInt']='int'; | ||
1019 | 53 | $GLOBALS['xmlrpcBoolean']='boolean'; | ||
1020 | 54 | $GLOBALS['xmlrpcDouble']='double'; | ||
1021 | 55 | $GLOBALS['xmlrpcString']='string'; | ||
1022 | 56 | $GLOBALS['xmlrpcDateTime']='dateTime.iso8601'; | ||
1023 | 57 | $GLOBALS['xmlrpcBase64']='base64'; | ||
1024 | 58 | $GLOBALS['xmlrpcArray']='array'; | ||
1025 | 59 | $GLOBALS['xmlrpcStruct']='struct'; | ||
1026 | 60 | $GLOBALS['xmlrpcValue']='undefined'; | ||
1027 | 61 | |||
1028 | 62 | $GLOBALS['xmlrpcTypes']=array( | ||
1029 | 63 | $GLOBALS['xmlrpcI4'] => 1, | ||
1030 | 64 | $GLOBALS['xmlrpcInt'] => 1, | ||
1031 | 65 | $GLOBALS['xmlrpcBoolean'] => 1, | ||
1032 | 66 | $GLOBALS['xmlrpcString'] => 1, | ||
1033 | 67 | $GLOBALS['xmlrpcDouble'] => 1, | ||
1034 | 68 | $GLOBALS['xmlrpcDateTime'] => 1, | ||
1035 | 69 | $GLOBALS['xmlrpcBase64'] => 1, | ||
1036 | 70 | $GLOBALS['xmlrpcArray'] => 2, | ||
1037 | 71 | $GLOBALS['xmlrpcStruct'] => 3 | ||
1038 | 72 | ); | ||
1039 | 73 | |||
1040 | 74 | $GLOBALS['xmlrpc_valid_parents'] = array( | ||
1041 | 75 | 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), | ||
1042 | 76 | 'BOOLEAN' => array('VALUE'), | ||
1043 | 77 | 'I4' => array('VALUE'), | ||
1044 | 78 | 'INT' => array('VALUE'), | ||
1045 | 79 | 'STRING' => array('VALUE'), | ||
1046 | 80 | 'DOUBLE' => array('VALUE'), | ||
1047 | 81 | 'DATETIME.ISO8601' => array('VALUE'), | ||
1048 | 82 | 'BASE64' => array('VALUE'), | ||
1049 | 83 | 'MEMBER' => array('STRUCT'), | ||
1050 | 84 | 'NAME' => array('MEMBER'), | ||
1051 | 85 | 'DATA' => array('ARRAY'), | ||
1052 | 86 | 'ARRAY' => array('VALUE'), | ||
1053 | 87 | 'STRUCT' => array('VALUE'), | ||
1054 | 88 | 'PARAM' => array('PARAMS'), | ||
1055 | 89 | 'METHODNAME' => array('METHODCALL'), | ||
1056 | 90 | 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), | ||
1057 | 91 | 'FAULT' => array('METHODRESPONSE'), | ||
1058 | 92 | 'NIL' => array('VALUE'), // only used when extension activated | ||
1059 | 93 | 'EX:NIL' => array('VALUE') // only used when extension activated | ||
1060 | 94 | ); | ||
1061 | 95 | |||
1062 | 96 | // define extra types for supporting NULL (useful for json or <NIL/>) | ||
1063 | 97 | $GLOBALS['xmlrpcNull']='null'; | ||
1064 | 98 | $GLOBALS['xmlrpcTypes']['null']=1; | ||
1065 | 99 | |||
1066 | 100 | // Not in use anymore since 2.0. Shall we remove it? | ||
1067 | 101 | /// @deprecated | ||
1068 | 102 | $GLOBALS['xmlEntities']=array( | ||
1069 | 103 | 'amp' => '&', | ||
1070 | 104 | 'quot' => '"', | ||
1071 | 105 | 'lt' => '<', | ||
1072 | 106 | 'gt' => '>', | ||
1073 | 107 | 'apos' => "'" | ||
1074 | 108 | ); | ||
1075 | 109 | |||
1076 | 110 | // tables used for transcoding different charsets into us-ascii xml | ||
1077 | 111 | |||
1078 | 112 | $GLOBALS['xml_iso88591_Entities']=array(); | ||
1079 | 113 | $GLOBALS['xml_iso88591_Entities']['in'] = array(); | ||
1080 | 114 | $GLOBALS['xml_iso88591_Entities']['out'] = array(); | ||
1081 | 115 | for ($i = 0; $i < 32; $i++) | ||
1082 | 116 | { | ||
1083 | 117 | $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); | ||
1084 | 118 | $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; | ||
1085 | 119 | } | ||
1086 | 120 | for ($i = 160; $i < 256; $i++) | ||
1087 | 121 | { | ||
1088 | 122 | $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); | ||
1089 | 123 | $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; | ||
1090 | 124 | } | ||
1091 | 125 | |||
1092 | 126 | /// @todo add to iso table the characters from cp_1252 range, i.e. 128 to 159? | ||
1093 | 127 | /// These will NOT be present in true ISO-8859-1, but will save the unwary | ||
1094 | 128 | /// windows user from sending junk (though no luck when reciving them...) | ||
1095 | 129 | /* | ||
1096 | 130 | $GLOBALS['xml_cp1252_Entities']=array(); | ||
1097 | 131 | for ($i = 128; $i < 160; $i++) | ||
1098 | 132 | { | ||
1099 | 133 | $GLOBALS['xml_cp1252_Entities']['in'][] = chr($i); | ||
1100 | 134 | } | ||
1101 | 135 | $GLOBALS['xml_cp1252_Entities']['out'] = array( | ||
1102 | 136 | '€', '?', '‚', 'ƒ', | ||
1103 | 137 | '„', '…', '†', '‡', | ||
1104 | 138 | 'ˆ', '‰', 'Š', '‹', | ||
1105 | 139 | 'Œ', '?', 'Ž', '?', | ||
1106 | 140 | '?', '‘', '’', '“', | ||
1107 | 141 | '”', '•', '–', '—', | ||
1108 | 142 | '˜', '™', 'š', '›', | ||
1109 | 143 | 'œ', '?', 'ž', 'Ÿ' | ||
1110 | 144 | ); | ||
1111 | 145 | */ | ||
1112 | 146 | |||
1113 | 147 | $GLOBALS['xmlrpcerr'] = array( | ||
1114 | 148 | 'unknown_method'=>1, | ||
1115 | 149 | 'invalid_return'=>2, | ||
1116 | 150 | 'incorrect_params'=>3, | ||
1117 | 151 | 'introspect_unknown'=>4, | ||
1118 | 152 | 'http_error'=>5, | ||
1119 | 153 | 'no_data'=>6, | ||
1120 | 154 | 'no_ssl'=>7, | ||
1121 | 155 | 'curl_fail'=>8, | ||
1122 | 156 | 'invalid_request'=>15, | ||
1123 | 157 | 'no_curl'=>16, | ||
1124 | 158 | 'server_error'=>17, | ||
1125 | 159 | 'multicall_error'=>18, | ||
1126 | 160 | 'multicall_notstruct'=>9, | ||
1127 | 161 | 'multicall_nomethod'=>10, | ||
1128 | 162 | 'multicall_notstring'=>11, | ||
1129 | 163 | 'multicall_recursion'=>12, | ||
1130 | 164 | 'multicall_noparams'=>13, | ||
1131 | 165 | 'multicall_notarray'=>14, | ||
1132 | 166 | |||
1133 | 167 | 'cannot_decompress'=>103, | ||
1134 | 168 | 'decompress_fail'=>104, | ||
1135 | 169 | 'dechunk_fail'=>105, | ||
1136 | 170 | 'server_cannot_decompress'=>106, | ||
1137 | 171 | 'server_decompress_fail'=>107 | ||
1138 | 172 | ); | ||
1139 | 173 | |||
1140 | 174 | $GLOBALS['xmlrpcstr'] = array( | ||
1141 | 175 | 'unknown_method'=>'Unknown method', | ||
1142 | 176 | 'invalid_return'=>'Invalid return payload: enable debugging to examine incoming payload', | ||
1143 | 177 | 'incorrect_params'=>'Incorrect parameters passed to method', | ||
1144 | 178 | 'introspect_unknown'=>"Can't introspect: method unknown", | ||
1145 | 179 | 'http_error'=>"Didn't receive 200 OK from remote server.", | ||
1146 | 180 | 'no_data'=>'No data received from server.', | ||
1147 | 181 | 'no_ssl'=>'No SSL support compiled in.', | ||
1148 | 182 | 'curl_fail'=>'CURL error', | ||
1149 | 183 | 'invalid_request'=>'Invalid request payload', | ||
1150 | 184 | 'no_curl'=>'No CURL support compiled in.', | ||
1151 | 185 | 'server_error'=>'Internal server error', | ||
1152 | 186 | 'multicall_error'=>'Received from server invalid multicall response', | ||
1153 | 187 | 'multicall_notstruct'=>'system.multicall expected struct', | ||
1154 | 188 | 'multicall_nomethod'=>'missing methodName', | ||
1155 | 189 | 'multicall_notstring'=>'methodName is not a string', | ||
1156 | 190 | 'multicall_recursion'=>'recursive system.multicall forbidden', | ||
1157 | 191 | 'multicall_noparams'=>'missing params', | ||
1158 | 192 | 'multicall_notarray'=>'params is not an array', | ||
1159 | 193 | |||
1160 | 194 | 'cannot_decompress'=>'Received from server compressed HTTP and cannot decompress', | ||
1161 | 195 | 'decompress_fail'=>'Received from server invalid compressed HTTP', | ||
1162 | 196 | 'dechunk_fail'=>'Received from server invalid chunked HTTP', | ||
1163 | 197 | 'server_cannot_decompress'=>'Received from client compressed HTTP request and cannot decompress', | ||
1164 | 198 | 'server_decompress_fail'=>'Received from client invalid compressed HTTP request' | ||
1165 | 199 | ); | ||
1166 | 200 | |||
1167 | 201 | // The charset encoding used by the server for received messages and | ||
1168 | 202 | // by the client for received responses when received charset cannot be determined | ||
1169 | 203 | // or is not supported | ||
1170 | 204 | $GLOBALS['xmlrpc_defencoding']='UTF-8'; | ||
1171 | 205 | |||
1172 | 206 | // The encoding used internally by PHP. | ||
1173 | 207 | // String values received as xml will be converted to this, and php strings will be converted to xml | ||
1174 | 208 | // as if having been coded with this | ||
1175 | 209 | $GLOBALS['xmlrpc_internalencoding']='ISO-8859-1'; | ||
1176 | 210 | |||
1177 | 211 | $GLOBALS['xmlrpcName']='XML-RPC for PHP'; | ||
1178 | 212 | $GLOBALS['xmlrpcVersion']='3.0.0.beta'; | ||
1179 | 213 | |||
1180 | 214 | // let user errors start at 800 | ||
1181 | 215 | $GLOBALS['xmlrpcerruser']=800; | ||
1182 | 216 | // let XML parse errors start at 100 | ||
1183 | 217 | $GLOBALS['xmlrpcerrxml']=100; | ||
1184 | 218 | |||
1185 | 219 | // formulate backslashes for escaping regexp | ||
1186 | 220 | // Not in use anymore since 2.0. Shall we remove it? | ||
1187 | 221 | /// @deprecated | ||
1188 | 222 | $GLOBALS['xmlrpc_backslash']=chr(92).chr(92); | ||
1189 | 223 | |||
1190 | 224 | // set to TRUE to enable correct decoding of <NIL/> and <EX:NIL/> values | ||
1191 | 225 | $GLOBALS['xmlrpc_null_extension']=false; | ||
1192 | 226 | |||
1193 | 227 | // set to TRUE to enable encoding of php NULL values to <EX:NIL/> instead of <NIL/> | ||
1194 | 228 | $GLOBALS['xmlrpc_null_apache_encoding']=false; | ||
1195 | 229 | |||
1196 | 230 | // used to store state during parsing | ||
1197 | 231 | // quick explanation of components: | ||
1198 | 232 | // ac - used to accumulate values | ||
1199 | 233 | // isf - used to indicate a parsing fault (2) or xmlrpcresp fault (1) | ||
1200 | 234 | // isf_reason - used for storing xmlrpcresp fault string | ||
1201 | 235 | // lv - used to indicate "looking for a value": implements | ||
1202 | 236 | // the logic to allow values with no types to be strings | ||
1203 | 237 | // params - used to store parameters in method calls | ||
1204 | 238 | // method - used to store method name | ||
1205 | 239 | // stack - array with genealogy of xml elements names: | ||
1206 | 240 | // used to validate nesting of xmlrpc elements | ||
1207 | 241 | $GLOBALS['_xh']=null; | ||
1208 | 242 | |||
1209 | 243 | /** | ||
1210 | 244 | * Convert a string to the correct XML representation in a target charset | ||
1211 | 245 | * To help correct communication of non-ascii chars inside strings, regardless | ||
1212 | 246 | * of the charset used when sending requests, parsing them, sending responses | ||
1213 | 247 | * and parsing responses, an option is to convert all non-ascii chars present in the message | ||
1214 | 248 | * into their equivalent 'charset entity'. Charset entities enumerated this way | ||
1215 | 249 | * are independent of the charset encoding used to transmit them, and all XML | ||
1216 | 250 | * parsers are bound to understand them. | ||
1217 | 251 | * Note that in the std case we are not sending a charset encoding mime type | ||
1218 | 252 | * along with http headers, so we are bound by RFC 3023 to emit strict us-ascii. | ||
1219 | 253 | * | ||
1220 | 254 | * @todo do a bit of basic benchmarking (strtr vs. str_replace) | ||
1221 | 255 | * @todo make usage of iconv() or recode_string() or mb_string() where available | ||
1222 | 256 | */ | ||
1223 | 257 | function xmlrpc_encode_entitites($data, $src_encoding='', $dest_encoding='') | ||
1224 | 258 | { | ||
1225 | 259 | if ($src_encoding == '') | ||
1226 | 260 | { | ||
1227 | 261 | // lame, but we know no better... | ||
1228 | 262 | $src_encoding = $GLOBALS['xmlrpc_internalencoding']; | ||
1229 | 263 | } | ||
1230 | 264 | |||
1231 | 265 | switch(strtoupper($src_encoding.'_'.$dest_encoding)) | ||
1232 | 266 | { | ||
1233 | 267 | case 'ISO-8859-1_': | ||
1234 | 268 | case 'ISO-8859-1_US-ASCII': | ||
1235 | 269 | $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); | ||
1236 | 270 | $escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data); | ||
1237 | 271 | break; | ||
1238 | 272 | case 'ISO-8859-1_UTF-8': | ||
1239 | 273 | $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); | ||
1240 | 274 | $escaped_data = utf8_encode($escaped_data); | ||
1241 | 275 | break; | ||
1242 | 276 | case 'ISO-8859-1_ISO-8859-1': | ||
1243 | 277 | case 'US-ASCII_US-ASCII': | ||
1244 | 278 | case 'US-ASCII_UTF-8': | ||
1245 | 279 | case 'US-ASCII_': | ||
1246 | 280 | case 'US-ASCII_ISO-8859-1': | ||
1247 | 281 | case 'UTF-8_UTF-8': | ||
1248 | 282 | //case 'CP1252_CP1252': | ||
1249 | 283 | $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); | ||
1250 | 284 | break; | ||
1251 | 285 | case 'UTF-8_': | ||
1252 | 286 | case 'UTF-8_US-ASCII': | ||
1253 | 287 | case 'UTF-8_ISO-8859-1': | ||
1254 | 288 | // NB: this will choke on invalid UTF-8, going most likely beyond EOF | ||
1255 | 289 | $escaped_data = ''; | ||
1256 | 290 | // be kind to users creating string xmlrpcvals out of different php types | ||
1257 | 291 | $data = (string) $data; | ||
1258 | 292 | $ns = strlen ($data); | ||
1259 | 293 | for ($nn = 0; $nn < $ns; $nn++) | ||
1260 | 294 | { | ||
1261 | 295 | $ch = $data[$nn]; | ||
1262 | 296 | $ii = ord($ch); | ||
1263 | 297 | //1 7 0bbbbbbb (127) | ||
1264 | 298 | if ($ii < 128) | ||
1265 | 299 | { | ||
1266 | 300 | /// @todo shall we replace this with a (supposedly) faster str_replace? | ||
1267 | 301 | switch($ii){ | ||
1268 | 302 | case 34: | ||
1269 | 303 | $escaped_data .= '"'; | ||
1270 | 304 | break; | ||
1271 | 305 | case 38: | ||
1272 | 306 | $escaped_data .= '&'; | ||
1273 | 307 | break; | ||
1274 | 308 | case 39: | ||
1275 | 309 | $escaped_data .= '''; | ||
1276 | 310 | break; | ||
1277 | 311 | case 60: | ||
1278 | 312 | $escaped_data .= '<'; | ||
1279 | 313 | break; | ||
1280 | 314 | case 62: | ||
1281 | 315 | $escaped_data .= '>'; | ||
1282 | 316 | break; | ||
1283 | 317 | default: | ||
1284 | 318 | $escaped_data .= $ch; | ||
1285 | 319 | } // switch | ||
1286 | 320 | } | ||
1287 | 321 | //2 11 110bbbbb 10bbbbbb (2047) | ||
1288 | 322 | else if ($ii>>5 == 6) | ||
1289 | 323 | { | ||
1290 | 324 | $b1 = ($ii & 31); | ||
1291 | 325 | $ii = ord($data[$nn+1]); | ||
1292 | 326 | $b2 = ($ii & 63); | ||
1293 | 327 | $ii = ($b1 * 64) + $b2; | ||
1294 | 328 | $ent = sprintf ('&#%d;', $ii); | ||
1295 | 329 | $escaped_data .= $ent; | ||
1296 | 330 | $nn += 1; | ||
1297 | 331 | } | ||
1298 | 332 | //3 16 1110bbbb 10bbbbbb 10bbbbbb | ||
1299 | 333 | else if ($ii>>4 == 14) | ||
1300 | 334 | { | ||
1301 | 335 | $b1 = ($ii & 15); | ||
1302 | 336 | $ii = ord($data[$nn+1]); | ||
1303 | 337 | $b2 = ($ii & 63); | ||
1304 | 338 | $ii = ord($data[$nn+2]); | ||
1305 | 339 | $b3 = ($ii & 63); | ||
1306 | 340 | $ii = ((($b1 * 64) + $b2) * 64) + $b3; | ||
1307 | 341 | $ent = sprintf ('&#%d;', $ii); | ||
1308 | 342 | $escaped_data .= $ent; | ||
1309 | 343 | $nn += 2; | ||
1310 | 344 | } | ||
1311 | 345 | //4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb | ||
1312 | 346 | else if ($ii>>3 == 30) | ||
1313 | 347 | { | ||
1314 | 348 | $b1 = ($ii & 7); | ||
1315 | 349 | $ii = ord($data[$nn+1]); | ||
1316 | 350 | $b2 = ($ii & 63); | ||
1317 | 351 | $ii = ord($data[$nn+2]); | ||
1318 | 352 | $b3 = ($ii & 63); | ||
1319 | 353 | $ii = ord($data[$nn+3]); | ||
1320 | 354 | $b4 = ($ii & 63); | ||
1321 | 355 | $ii = ((((($b1 * 64) + $b2) * 64) + $b3) * 64) + $b4; | ||
1322 | 356 | $ent = sprintf ('&#%d;', $ii); | ||
1323 | 357 | $escaped_data .= $ent; | ||
1324 | 358 | $nn += 3; | ||
1325 | 359 | } | ||
1326 | 360 | } | ||
1327 | 361 | break; | ||
1328 | 362 | /* | ||
1329 | 363 | case 'CP1252_': | ||
1330 | 364 | case 'CP1252_US-ASCII': | ||
1331 | 365 | $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); | ||
1332 | 366 | $escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data); | ||
1333 | 367 | $escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data); | ||
1334 | 368 | break; | ||
1335 | 369 | case 'CP1252_UTF-8': | ||
1336 | 370 | $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); | ||
1337 | 371 | /// @todo we could use real UTF8 chars here instead of xml entities... (note that utf_8 encode all allone will NOT convert them) | ||
1338 | 372 | $escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data); | ||
1339 | 373 | $escaped_data = utf8_encode($escaped_data); | ||
1340 | 374 | break; | ||
1341 | 375 | case 'CP1252_ISO-8859-1': | ||
1342 | 376 | $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); | ||
1343 | 377 | // we might as well replave all funky chars with a '?' here, but we are kind and leave it to the receiving application layer to decide what to do with these weird entities... | ||
1344 | 378 | $escaped_data = str_replace($GLOBALS['xml_cp1252_Entities']['in'], $GLOBALS['xml_cp1252_Entities']['out'], $escaped_data); | ||
1345 | 379 | break; | ||
1346 | 380 | */ | ||
1347 | 381 | default: | ||
1348 | 382 | $escaped_data = ''; | ||
1349 | 383 | error_log("Converting from $src_encoding to $dest_encoding: not supported..."); | ||
1350 | 384 | } | ||
1351 | 385 | return $escaped_data; | ||
1352 | 386 | } | ||
1353 | 387 | |||
1354 | 388 | /// xml parser handler function for opening element tags | ||
1355 | 389 | function xmlrpc_se($parser, $name, $attrs, $accept_single_vals=false) | ||
1356 | 390 | { | ||
1357 | 391 | // if invalid xmlrpc already detected, skip all processing | ||
1358 | 392 | if ($GLOBALS['_xh']['isf'] < 2) | ||
1359 | 393 | { | ||
1360 | 394 | // check for correct element nesting | ||
1361 | 395 | // top level element can only be of 2 types | ||
1362 | 396 | /// @todo optimization creep: save this check into a bool variable, instead of using count() every time: | ||
1363 | 397 | /// there is only a single top level element in xml anyway | ||
1364 | 398 | if (count($GLOBALS['_xh']['stack']) == 0) | ||
1365 | 399 | { | ||
1366 | 400 | if ($name != 'METHODRESPONSE' && $name != 'METHODCALL' && ( | ||
1367 | 401 | $name != 'VALUE' && !$accept_single_vals)) | ||
1368 | 402 | { | ||
1369 | 403 | $GLOBALS['_xh']['isf'] = 2; | ||
1370 | 404 | $GLOBALS['_xh']['isf_reason'] = 'missing top level xmlrpc element'; | ||
1371 | 405 | return; | ||
1372 | 406 | } | ||
1373 | 407 | else | ||
1374 | 408 | { | ||
1375 | 409 | $GLOBALS['_xh']['rt'] = strtolower($name); | ||
1376 | 410 | $GLOBALS['_xh']['rt'] = strtolower($name); | ||
1377 | 411 | } | ||
1378 | 412 | } | ||
1379 | 413 | else | ||
1380 | 414 | { | ||
1381 | 415 | // not top level element: see if parent is OK | ||
1382 | 416 | $parent = end($GLOBALS['_xh']['stack']); | ||
1383 | 417 | if (!array_key_exists($name, $GLOBALS['xmlrpc_valid_parents']) || !in_array($parent, $GLOBALS['xmlrpc_valid_parents'][$name])) | ||
1384 | 418 | { | ||
1385 | 419 | $GLOBALS['_xh']['isf'] = 2; | ||
1386 | 420 | $GLOBALS['_xh']['isf_reason'] = "xmlrpc element $name cannot be child of $parent"; | ||
1387 | 421 | return; | ||
1388 | 422 | } | ||
1389 | 423 | } | ||
1390 | 424 | |||
1391 | 425 | switch($name) | ||
1392 | 426 | { | ||
1393 | 427 | // optimize for speed switch cases: most common cases first | ||
1394 | 428 | case 'VALUE': | ||
1395 | 429 | /// @todo we could check for 2 VALUE elements inside a MEMBER or PARAM element | ||
1396 | 430 | $GLOBALS['_xh']['vt']='value'; // indicator: no value found yet | ||
1397 | 431 | $GLOBALS['_xh']['ac']=''; | ||
1398 | 432 | $GLOBALS['_xh']['lv']=1; | ||
1399 | 433 | $GLOBALS['_xh']['php_class']=null; | ||
1400 | 434 | break; | ||
1401 | 435 | case 'I4': | ||
1402 | 436 | case 'INT': | ||
1403 | 437 | case 'STRING': | ||
1404 | 438 | case 'BOOLEAN': | ||
1405 | 439 | case 'DOUBLE': | ||
1406 | 440 | case 'DATETIME.ISO8601': | ||
1407 | 441 | case 'BASE64': | ||
1408 | 442 | if ($GLOBALS['_xh']['vt']!='value') | ||
1409 | 443 | { | ||
1410 | 444 | //two data elements inside a value: an error occurred! | ||
1411 | 445 | $GLOBALS['_xh']['isf'] = 2; | ||
1412 | 446 | $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; | ||
1413 | 447 | return; | ||
1414 | 448 | } | ||
1415 | 449 | $GLOBALS['_xh']['ac']=''; // reset the accumulator | ||
1416 | 450 | break; | ||
1417 | 451 | case 'STRUCT': | ||
1418 | 452 | case 'ARRAY': | ||
1419 | 453 | if ($GLOBALS['_xh']['vt']!='value') | ||
1420 | 454 | { | ||
1421 | 455 | //two data elements inside a value: an error occurred! | ||
1422 | 456 | $GLOBALS['_xh']['isf'] = 2; | ||
1423 | 457 | $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; | ||
1424 | 458 | return; | ||
1425 | 459 | } | ||
1426 | 460 | // create an empty array to hold child values, and push it onto appropriate stack | ||
1427 | 461 | $cur_val = array(); | ||
1428 | 462 | $cur_val['values'] = array(); | ||
1429 | 463 | $cur_val['type'] = $name; | ||
1430 | 464 | // check for out-of-band information to rebuild php objs | ||
1431 | 465 | // and in case it is found, save it | ||
1432 | 466 | if (@isset($attrs['PHP_CLASS'])) | ||
1433 | 467 | { | ||
1434 | 468 | $cur_val['php_class'] = $attrs['PHP_CLASS']; | ||
1435 | 469 | } | ||
1436 | 470 | $GLOBALS['_xh']['valuestack'][] = $cur_val; | ||
1437 | 471 | $GLOBALS['_xh']['vt']='data'; // be prepared for a data element next | ||
1438 | 472 | break; | ||
1439 | 473 | case 'DATA': | ||
1440 | 474 | if ($GLOBALS['_xh']['vt']!='data') | ||
1441 | 475 | { | ||
1442 | 476 | //two data elements inside a value: an error occurred! | ||
1443 | 477 | $GLOBALS['_xh']['isf'] = 2; | ||
1444 | 478 | $GLOBALS['_xh']['isf_reason'] = "found two data elements inside an array element"; | ||
1445 | 479 | return; | ||
1446 | 480 | } | ||
1447 | 481 | case 'METHODCALL': | ||
1448 | 482 | case 'METHODRESPONSE': | ||
1449 | 483 | case 'PARAMS': | ||
1450 | 484 | // valid elements that add little to processing | ||
1451 | 485 | break; | ||
1452 | 486 | case 'METHODNAME': | ||
1453 | 487 | case 'NAME': | ||
1454 | 488 | /// @todo we could check for 2 NAME elements inside a MEMBER element | ||
1455 | 489 | $GLOBALS['_xh']['ac']=''; | ||
1456 | 490 | break; | ||
1457 | 491 | case 'FAULT': | ||
1458 | 492 | $GLOBALS['_xh']['isf']=1; | ||
1459 | 493 | break; | ||
1460 | 494 | case 'MEMBER': | ||
1461 | 495 | $GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name']=''; // set member name to null, in case we do not find in the xml later on | ||
1462 | 496 | //$GLOBALS['_xh']['ac']=''; | ||
1463 | 497 | // Drop trough intentionally | ||
1464 | 498 | case 'PARAM': | ||
1465 | 499 | // clear value type, so we can check later if no value has been passed for this param/member | ||
1466 | 500 | $GLOBALS['_xh']['vt']=null; | ||
1467 | 501 | break; | ||
1468 | 502 | case 'NIL': | ||
1469 | 503 | case 'EX:NIL': | ||
1470 | 504 | if ($GLOBALS['xmlrpc_null_extension']) | ||
1471 | 505 | { | ||
1472 | 506 | if ($GLOBALS['_xh']['vt']!='value') | ||
1473 | 507 | { | ||
1474 | 508 | //two data elements inside a value: an error occurred! | ||
1475 | 509 | $GLOBALS['_xh']['isf'] = 2; | ||
1476 | 510 | $GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value"; | ||
1477 | 511 | return; | ||
1478 | 512 | } | ||
1479 | 513 | $GLOBALS['_xh']['ac']=''; // reset the accumulator | ||
1480 | 514 | break; | ||
1481 | 515 | } | ||
1482 | 516 | // we do not support the <NIL/> extension, so | ||
1483 | 517 | // drop through intentionally | ||
1484 | 518 | default: | ||
1485 | 519 | /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!! | ||
1486 | 520 | $GLOBALS['_xh']['isf'] = 2; | ||
1487 | 521 | $GLOBALS['_xh']['isf_reason'] = "found not-xmlrpc xml element $name"; | ||
1488 | 522 | break; | ||
1489 | 523 | } | ||
1490 | 524 | |||
1491 | 525 | // Save current element name to stack, to validate nesting | ||
1492 | 526 | $GLOBALS['_xh']['stack'][] = $name; | ||
1493 | 527 | |||
1494 | 528 | /// @todo optimization creep: move this inside the big switch() above | ||
1495 | 529 | if($name!='VALUE') | ||
1496 | 530 | { | ||
1497 | 531 | $GLOBALS['_xh']['lv']=0; | ||
1498 | 532 | } | ||
1499 | 533 | } | ||
1500 | 534 | } | ||
1501 | 535 | |||
1502 | 536 | /// Used in decoding xml chunks that might represent single xmlrpc values | ||
1503 | 537 | function xmlrpc_se_any($parser, $name, $attrs) | ||
1504 | 538 | { | ||
1505 | 539 | xmlrpc_se($parser, $name, $attrs, true); | ||
1506 | 540 | } | ||
1507 | 541 | |||
1508 | 542 | /// xml parser handler function for close element tags | ||
1509 | 543 | function xmlrpc_ee($parser, $name, $rebuild_xmlrpcvals = true) | ||
1510 | 544 | { | ||
1511 | 545 | if ($GLOBALS['_xh']['isf'] < 2) | ||
1512 | 546 | { | ||
1513 | 547 | // push this element name from stack | ||
1514 | 548 | // NB: if XML validates, correct opening/closing is guaranteed and | ||
1515 | 549 | // we do not have to check for $name == $curr_elem. | ||
1516 | 550 | // we also checked for proper nesting at start of elements... | ||
1517 | 551 | $curr_elem = array_pop($GLOBALS['_xh']['stack']); | ||
1518 | 552 | |||
1519 | 553 | switch($name) | ||
1520 | 554 | { | ||
1521 | 555 | case 'VALUE': | ||
1522 | 556 | // This if() detects if no scalar was inside <VALUE></VALUE> | ||
1523 | 557 | if ($GLOBALS['_xh']['vt']=='value') | ||
1524 | 558 | { | ||
1525 | 559 | $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; | ||
1526 | 560 | $GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcString']; | ||
1527 | 561 | } | ||
1528 | 562 | |||
1529 | 563 | if ($rebuild_xmlrpcvals) | ||
1530 | 564 | { | ||
1531 | 565 | // build the xmlrpc val out of the data received, and substitute it | ||
1532 | 566 | $temp = new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']); | ||
1533 | 567 | // in case we got info about underlying php class, save it | ||
1534 | 568 | // in the object we're rebuilding | ||
1535 | 569 | if (isset($GLOBALS['_xh']['php_class'])) | ||
1536 | 570 | $temp->_php_class = $GLOBALS['_xh']['php_class']; | ||
1537 | 571 | // check if we are inside an array or struct: | ||
1538 | 572 | // if value just built is inside an array, let's move it into array on the stack | ||
1539 | 573 | $vscount = count($GLOBALS['_xh']['valuestack']); | ||
1540 | 574 | if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY') | ||
1541 | 575 | { | ||
1542 | 576 | $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $temp; | ||
1543 | 577 | } | ||
1544 | 578 | else | ||
1545 | 579 | { | ||
1546 | 580 | $GLOBALS['_xh']['value'] = $temp; | ||
1547 | 581 | } | ||
1548 | 582 | } | ||
1549 | 583 | else | ||
1550 | 584 | { | ||
1551 | 585 | /// @todo this needs to treat correctly php-serialized objects, | ||
1552 | 586 | /// since std deserializing is done by php_xmlrpc_decode, | ||
1553 | 587 | /// which we will not be calling... | ||
1554 | 588 | if (isset($GLOBALS['_xh']['php_class'])) | ||
1555 | 589 | { | ||
1556 | 590 | } | ||
1557 | 591 | |||
1558 | 592 | // check if we are inside an array or struct: | ||
1559 | 593 | // if value just built is inside an array, let's move it into array on the stack | ||
1560 | 594 | $vscount = count($GLOBALS['_xh']['valuestack']); | ||
1561 | 595 | if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY') | ||
1562 | 596 | { | ||
1563 | 597 | $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $GLOBALS['_xh']['value']; | ||
1564 | 598 | } | ||
1565 | 599 | } | ||
1566 | 600 | break; | ||
1567 | 601 | case 'BOOLEAN': | ||
1568 | 602 | case 'I4': | ||
1569 | 603 | case 'INT': | ||
1570 | 604 | case 'STRING': | ||
1571 | 605 | case 'DOUBLE': | ||
1572 | 606 | case 'DATETIME.ISO8601': | ||
1573 | 607 | case 'BASE64': | ||
1574 | 608 | $GLOBALS['_xh']['vt']=strtolower($name); | ||
1575 | 609 | /// @todo: optimization creep - remove the if/elseif cycle below | ||
1576 | 610 | /// since the case() in which we are already did that | ||
1577 | 611 | if ($name=='STRING') | ||
1578 | 612 | { | ||
1579 | 613 | $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; | ||
1580 | 614 | } | ||
1581 | 615 | elseif ($name=='DATETIME.ISO8601') | ||
1582 | 616 | { | ||
1583 | 617 | if (!preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $GLOBALS['_xh']['ac'])) | ||
1584 | 618 | { | ||
1585 | 619 | error_log('XML-RPC: invalid value received in DATETIME: '.$GLOBALS['_xh']['ac']); | ||
1586 | 620 | } | ||
1587 | 621 | $GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcDateTime']; | ||
1588 | 622 | $GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac']; | ||
1589 | 623 | } | ||
1590 | 624 | elseif ($name=='BASE64') | ||
1591 | 625 | { | ||
1592 | 626 | /// @todo check for failure of base64 decoding / catch warnings | ||
1593 | 627 | $GLOBALS['_xh']['value']=base64_decode($GLOBALS['_xh']['ac']); | ||
1594 | 628 | } | ||
1595 | 629 | elseif ($name=='BOOLEAN') | ||
1596 | 630 | { | ||
1597 | 631 | // special case here: we translate boolean 1 or 0 into PHP | ||
1598 | 632 | // constants true or false. | ||
1599 | 633 | // Strings 'true' and 'false' are accepted, even though the | ||
1600 | 634 | // spec never mentions them (see eg. Blogger api docs) | ||
1601 | 635 | // NB: this simple checks helps a lot sanitizing input, ie no | ||
1602 | 636 | // security problems around here | ||
1603 | 637 | if ($GLOBALS['_xh']['ac']=='1' || strcasecmp($GLOBALS['_xh']['ac'], 'true') == 0) | ||
1604 | 638 | { | ||
1605 | 639 | $GLOBALS['_xh']['value']=true; | ||
1606 | 640 | } | ||
1607 | 641 | else | ||
1608 | 642 | { | ||
1609 | 643 | // log if receiveing something strange, even though we set the value to false anyway | ||
1610 | 644 | if ($GLOBALS['_xh']['ac']!='0' && strcasecmp($GLOBALS['_xh']['ac'], 'false') != 0) | ||
1611 | 645 | error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh']['ac']); | ||
1612 | 646 | $GLOBALS['_xh']['value']=false; | ||
1613 | 647 | } | ||
1614 | 648 | } | ||
1615 | 649 | elseif ($name=='DOUBLE') | ||
1616 | 650 | { | ||
1617 | 651 | // we have a DOUBLE | ||
1618 | 652 | // we must check that only 0123456789-.<space> are characters here | ||
1619 | 653 | // NOTE: regexp could be much stricter than this... | ||
1620 | 654 | if (!preg_match('/^[+-eE0123456789 \t.]+$/', $GLOBALS['_xh']['ac'])) | ||
1621 | 655 | { | ||
1622 | 656 | /// @todo: find a better way of throwing an error than this! | ||
1623 | 657 | error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh']['ac']); | ||
1624 | 658 | $GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND'; | ||
1625 | 659 | } | ||
1626 | 660 | else | ||
1627 | 661 | { | ||
1628 | 662 | // it's ok, add it on | ||
1629 | 663 | $GLOBALS['_xh']['value']=(double)$GLOBALS['_xh']['ac']; | ||
1630 | 664 | } | ||
1631 | 665 | } | ||
1632 | 666 | else | ||
1633 | 667 | { | ||
1634 | 668 | // we have an I4/INT | ||
1635 | 669 | // we must check that only 0123456789-<space> are characters here | ||
1636 | 670 | if (!preg_match('/^[+-]?[0123456789 \t]+$/', $GLOBALS['_xh']['ac'])) | ||
1637 | 671 | { | ||
1638 | 672 | /// @todo find a better way of throwing an error than this! | ||
1639 | 673 | error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh']['ac']); | ||
1640 | 674 | $GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND'; | ||
1641 | 675 | } | ||
1642 | 676 | else | ||
1643 | 677 | { | ||
1644 | 678 | // it's ok, add it on | ||
1645 | 679 | $GLOBALS['_xh']['value']=(int)$GLOBALS['_xh']['ac']; | ||
1646 | 680 | } | ||
1647 | 681 | } | ||
1648 | 682 | //$GLOBALS['_xh']['ac']=''; // is this necessary? | ||
1649 | 683 | $GLOBALS['_xh']['lv']=3; // indicate we've found a value | ||
1650 | 684 | break; | ||
1651 | 685 | case 'NAME': | ||
1652 | 686 | $GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name'] = $GLOBALS['_xh']['ac']; | ||
1653 | 687 | break; | ||
1654 | 688 | case 'MEMBER': | ||
1655 | 689 | //$GLOBALS['_xh']['ac']=''; // is this necessary? | ||
1656 | 690 | // add to array in the stack the last element built, | ||
1657 | 691 | // unless no VALUE was found | ||
1658 | 692 | if ($GLOBALS['_xh']['vt']) | ||
1659 | 693 | { | ||
1660 | 694 | $vscount = count($GLOBALS['_xh']['valuestack']); | ||
1661 | 695 | $GLOBALS['_xh']['valuestack'][$vscount-1]['values'][$GLOBALS['_xh']['valuestack'][$vscount-1]['name']] = $GLOBALS['_xh']['value']; | ||
1662 | 696 | } else | ||
1663 | 697 | error_log('XML-RPC: missing VALUE inside STRUCT in received xml'); | ||
1664 | 698 | break; | ||
1665 | 699 | case 'DATA': | ||
1666 | 700 | //$GLOBALS['_xh']['ac']=''; // is this necessary? | ||
1667 | 701 | $GLOBALS['_xh']['vt']=null; // reset this to check for 2 data elements in a row - even if they're empty | ||
1668 | 702 | break; | ||
1669 | 703 | case 'STRUCT': | ||
1670 | 704 | case 'ARRAY': | ||
1671 | 705 | // fetch out of stack array of values, and promote it to current value | ||
1672 | 706 | $curr_val = array_pop($GLOBALS['_xh']['valuestack']); | ||
1673 | 707 | $GLOBALS['_xh']['value'] = $curr_val['values']; | ||
1674 | 708 | $GLOBALS['_xh']['vt']=strtolower($name); | ||
1675 | 709 | if (isset($curr_val['php_class'])) | ||
1676 | 710 | { | ||
1677 | 711 | $GLOBALS['_xh']['php_class'] = $curr_val['php_class']; | ||
1678 | 712 | } | ||
1679 | 713 | break; | ||
1680 | 714 | case 'PARAM': | ||
1681 | 715 | // add to array of params the current value, | ||
1682 | 716 | // unless no VALUE was found | ||
1683 | 717 | if ($GLOBALS['_xh']['vt']) | ||
1684 | 718 | { | ||
1685 | 719 | $GLOBALS['_xh']['params'][]=$GLOBALS['_xh']['value']; | ||
1686 | 720 | $GLOBALS['_xh']['pt'][]=$GLOBALS['_xh']['vt']; | ||
1687 | 721 | } | ||
1688 | 722 | else | ||
1689 | 723 | error_log('XML-RPC: missing VALUE inside PARAM in received xml'); | ||
1690 | 724 | break; | ||
1691 | 725 | case 'METHODNAME': | ||
1692 | 726 | $GLOBALS['_xh']['method']=preg_replace('/^[\n\r\t ]+/', '', $GLOBALS['_xh']['ac']); | ||
1693 | 727 | break; | ||
1694 | 728 | case 'NIL': | ||
1695 | 729 | case 'EX:NIL': | ||
1696 | 730 | if ($GLOBALS['xmlrpc_null_extension']) | ||
1697 | 731 | { | ||
1698 | 732 | $GLOBALS['_xh']['vt']='null'; | ||
1699 | 733 | $GLOBALS['_xh']['value']=null; | ||
1700 | 734 | $GLOBALS['_xh']['lv']=3; | ||
1701 | 735 | break; | ||
1702 | 736 | } | ||
1703 | 737 | // drop through intentionally if nil extension not enabled | ||
1704 | 738 | case 'PARAMS': | ||
1705 | 739 | case 'FAULT': | ||
1706 | 740 | case 'METHODCALL': | ||
1707 | 741 | case 'METHORESPONSE': | ||
1708 | 742 | break; | ||
1709 | 743 | default: | ||
1710 | 744 | // End of INVALID ELEMENT! | ||
1711 | 745 | // shall we add an assert here for unreachable code??? | ||
1712 | 746 | break; | ||
1713 | 747 | } | ||
1714 | 748 | } | ||
1715 | 749 | } | ||
1716 | 750 | |||
1717 | 751 | /// Used in decoding xmlrpc requests/responses without rebuilding xmlrpc values | ||
1718 | 752 | function xmlrpc_ee_fast($parser, $name) | ||
1719 | 753 | { | ||
1720 | 754 | xmlrpc_ee($parser, $name, false); | ||
1721 | 755 | } | ||
1722 | 756 | |||
1723 | 757 | /// xml parser handler function for character data | ||
1724 | 758 | function xmlrpc_cd($parser, $data) | ||
1725 | 759 | { | ||
1726 | 760 | // skip processing if xml fault already detected | ||
1727 | 761 | if ($GLOBALS['_xh']['isf'] < 2) | ||
1728 | 762 | { | ||
1729 | 763 | // "lookforvalue==3" means that we've found an entire value | ||
1730 | 764 | // and should discard any further character data | ||
1731 | 765 | if($GLOBALS['_xh']['lv']!=3) | ||
1732 | 766 | { | ||
1733 | 767 | // G. Giunta 2006-08-23: useless change of 'lv' from 1 to 2 | ||
1734 | 768 | //if($GLOBALS['_xh']['lv']==1) | ||
1735 | 769 | //{ | ||
1736 | 770 | // if we've found text and we're just in a <value> then | ||
1737 | 771 | // say we've found a value | ||
1738 | 772 | //$GLOBALS['_xh']['lv']=2; | ||
1739 | 773 | //} | ||
1740 | 774 | // we always initialize the accumulator before starting parsing, anyway... | ||
1741 | 775 | //if(!@isset($GLOBALS['_xh']['ac'])) | ||
1742 | 776 | //{ | ||
1743 | 777 | // $GLOBALS['_xh']['ac'] = ''; | ||
1744 | 778 | //} | ||
1745 | 779 | $GLOBALS['_xh']['ac'].=$data; | ||
1746 | 780 | } | ||
1747 | 781 | } | ||
1748 | 782 | } | ||
1749 | 783 | |||
1750 | 784 | /// xml parser handler function for 'other stuff', ie. not char data or | ||
1751 | 785 | /// element start/end tag. In fact it only gets called on unknown entities... | ||
1752 | 786 | function xmlrpc_dh($parser, $data) | ||
1753 | 787 | { | ||
1754 | 788 | // skip processing if xml fault already detected | ||
1755 | 789 | if ($GLOBALS['_xh']['isf'] < 2) | ||
1756 | 790 | { | ||
1757 | 791 | if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';') | ||
1758 | 792 | { | ||
1759 | 793 | // G. Giunta 2006-08-25: useless change of 'lv' from 1 to 2 | ||
1760 | 794 | //if($GLOBALS['_xh']['lv']==1) | ||
1761 | 795 | //{ | ||
1762 | 796 | // $GLOBALS['_xh']['lv']=2; | ||
1763 | 797 | //} | ||
1764 | 798 | $GLOBALS['_xh']['ac'].=$data; | ||
1765 | 799 | } | ||
1766 | 800 | } | ||
1767 | 801 | return true; | ||
1768 | 802 | } | ||
1769 | 803 | |||
1770 | 804 | class xmlrpc_client | ||
1771 | 805 | { | ||
1772 | 806 | var $path; | ||
1773 | 807 | var $server; | ||
1774 | 808 | var $port=0; | ||
1775 | 809 | var $method='http'; | ||
1776 | 810 | var $errno; | ||
1777 | 811 | var $errstr; | ||
1778 | 812 | var $debug=0; | ||
1779 | 813 | var $username=''; | ||
1780 | 814 | var $password=''; | ||
1781 | 815 | var $authtype=1; | ||
1782 | 816 | var $cert=''; | ||
1783 | 817 | var $certpass=''; | ||
1784 | 818 | var $cacert=''; | ||
1785 | 819 | var $cacertdir=''; | ||
1786 | 820 | var $key=''; | ||
1787 | 821 | var $keypass=''; | ||
1788 | 822 | var $verifypeer=true; | ||
1789 | 823 | var $verifyhost=1; | ||
1790 | 824 | var $no_multicall=false; | ||
1791 | 825 | var $proxy=''; | ||
1792 | 826 | var $proxyport=0; | ||
1793 | 827 | var $proxy_user=''; | ||
1794 | 828 | var $proxy_pass=''; | ||
1795 | 829 | var $proxy_authtype=1; | ||
1796 | 830 | var $cookies=array(); | ||
1797 | 831 | var $extracurlopts=array(); | ||
1798 | 832 | |||
1799 | 833 | /** | ||
1800 | 834 | * List of http compression methods accepted by the client for responses. | ||
1801 | 835 | * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib | ||
1802 | 836 | * | ||
1803 | 837 | * NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since | ||
1804 | 838 | * in those cases it will be up to CURL to decide the compression methods | ||
1805 | 839 | * it supports. You might check for the presence of 'zlib' in the output of | ||
1806 | 840 | * curl_version() to determine wheter compression is supported or not | ||
1807 | 841 | */ | ||
1808 | 842 | var $accepted_compression = array(); | ||
1809 | 843 | /** | ||
1810 | 844 | * Name of compression scheme to be used for sending requests. | ||
1811 | 845 | * Either null, gzip or deflate | ||
1812 | 846 | */ | ||
1813 | 847 | var $request_compression = ''; | ||
1814 | 848 | /** | ||
1815 | 849 | * CURL handle: used for keep-alive connections (PHP 4.3.8 up, see: | ||
1816 | 850 | * http://curl.haxx.se/docs/faq.html#7.3) | ||
1817 | 851 | */ | ||
1818 | 852 | var $xmlrpc_curl_handle = null; | ||
1819 | 853 | /// Wheter to use persistent connections for http 1.1 and https | ||
1820 | 854 | var $keepalive = false; | ||
1821 | 855 | /// Charset encodings that can be decoded without problems by the client | ||
1822 | 856 | var $accepted_charset_encodings = array(); | ||
1823 | 857 | /// Charset encoding to be used in serializing request. NULL = use ASCII | ||
1824 | 858 | var $request_charset_encoding = ''; | ||
1825 | 859 | /** | ||
1826 | 860 | * Decides the content of xmlrpcresp objects returned by calls to send() | ||
1827 | 861 | * valid strings are 'xmlrpcvals', 'phpvals' or 'xml' | ||
1828 | 862 | */ | ||
1829 | 863 | var $return_type = 'xmlrpcvals'; | ||
1830 | 864 | /** | ||
1831 | 865 | * Sent to servers in http headers | ||
1832 | 866 | */ | ||
1833 | 867 | var $user_agent; | ||
1834 | 868 | |||
1835 | 869 | /** | ||
1836 | 870 | * @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php | ||
1837 | 871 | * @param string $server the server name / ip address | ||
1838 | 872 | * @param integer $port the port the server is listening on, defaults to 80 or 443 depending on protocol used | ||
1839 | 873 | * @param string $method the http protocol variant: defaults to 'http', 'https' and 'http11' can be used if CURL is installed | ||
1840 | 874 | */ | ||
1841 | 875 | function xmlrpc_client($path, $server='', $port='', $method='') | ||
1842 | 876 | { | ||
1843 | 877 | // allow user to specify all params in $path | ||
1844 | 878 | if($server == '' and $port == '' and $method == '') | ||
1845 | 879 | { | ||
1846 | 880 | $parts = parse_url($path); | ||
1847 | 881 | $server = $parts['host']; | ||
1848 | 882 | $path = isset($parts['path']) ? $parts['path'] : ''; | ||
1849 | 883 | if(isset($parts['query'])) | ||
1850 | 884 | { | ||
1851 | 885 | $path .= '?'.$parts['query']; | ||
1852 | 886 | } | ||
1853 | 887 | if(isset($parts['fragment'])) | ||
1854 | 888 | { | ||
1855 | 889 | $path .= '#'.$parts['fragment']; | ||
1856 | 890 | } | ||
1857 | 891 | if(isset($parts['port'])) | ||
1858 | 892 | { | ||
1859 | 893 | $port = $parts['port']; | ||
1860 | 894 | } | ||
1861 | 895 | if(isset($parts['scheme'])) | ||
1862 | 896 | { | ||
1863 | 897 | $method = $parts['scheme']; | ||
1864 | 898 | } | ||
1865 | 899 | if(isset($parts['user'])) | ||
1866 | 900 | { | ||
1867 | 901 | $this->username = $parts['user']; | ||
1868 | 902 | } | ||
1869 | 903 | if(isset($parts['pass'])) | ||
1870 | 904 | { | ||
1871 | 905 | $this->password = $parts['pass']; | ||
1872 | 906 | } | ||
1873 | 907 | } | ||
1874 | 908 | if($path == '' || $path[0] != '/') | ||
1875 | 909 | { | ||
1876 | 910 | $this->path='/'.$path; | ||
1877 | 911 | } | ||
1878 | 912 | else | ||
1879 | 913 | { | ||
1880 | 914 | $this->path=$path; | ||
1881 | 915 | } | ||
1882 | 916 | $this->server=$server; | ||
1883 | 917 | if($port != '') | ||
1884 | 918 | { | ||
1885 | 919 | $this->port=$port; | ||
1886 | 920 | } | ||
1887 | 921 | if($method != '') | ||
1888 | 922 | { | ||
1889 | 923 | $this->method=$method; | ||
1890 | 924 | } | ||
1891 | 925 | |||
1892 | 926 | // if ZLIB is enabled, let the client by default accept compressed responses | ||
1893 | 927 | if(function_exists('gzinflate') || ( | ||
1894 | 928 | function_exists('curl_init') && (($info = curl_version()) && | ||
1895 | 929 | ((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version']))) | ||
1896 | 930 | )) | ||
1897 | 931 | { | ||
1898 | 932 | $this->accepted_compression = array('gzip', 'deflate'); | ||
1899 | 933 | } | ||
1900 | 934 | |||
1901 | 935 | // keepalives: enabled by default | ||
1902 | 936 | $this->keepalive = true; | ||
1903 | 937 | |||
1904 | 938 | // by default the xml parser can support these 3 charset encodings | ||
1905 | 939 | $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); | ||
1906 | 940 | |||
1907 | 941 | // initialize user_agent string | ||
1908 | 942 | $this->user_agent = $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion']; | ||
1909 | 943 | } | ||
1910 | 944 | |||
1911 | 945 | /** | ||
1912 | 946 | * Enables/disables the echoing to screen of the xmlrpc responses received | ||
1913 | 947 | * @param integer $debug values 0, 1 and 2 are supported (2 = echo sent msg too, before received response) | ||
1914 | 948 | * @access public | ||
1915 | 949 | */ | ||
1916 | 950 | function setDebug($in) | ||
1917 | 951 | { | ||
1918 | 952 | $this->debug=$in; | ||
1919 | 953 | } | ||
1920 | 954 | |||
1921 | 955 | /** | ||
1922 | 956 | * Add some http BASIC AUTH credentials, used by the client to authenticate | ||
1923 | 957 | * @param string $u username | ||
1924 | 958 | * @param string $p password | ||
1925 | 959 | * @param integer $t auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC (basic auth) | ||
1926 | 960 | * @access public | ||
1927 | 961 | */ | ||
1928 | 962 | function setCredentials($u, $p, $t=1) | ||
1929 | 963 | { | ||
1930 | 964 | $this->username=$u; | ||
1931 | 965 | $this->password=$p; | ||
1932 | 966 | $this->authtype=$t; | ||
1933 | 967 | } | ||
1934 | 968 | |||
1935 | 969 | /** | ||
1936 | 970 | * Add a client-side https certificate | ||
1937 | 971 | * @param string $cert | ||
1938 | 972 | * @param string $certpass | ||
1939 | 973 | * @access public | ||
1940 | 974 | */ | ||
1941 | 975 | function setCertificate($cert, $certpass) | ||
1942 | 976 | { | ||
1943 | 977 | $this->cert = $cert; | ||
1944 | 978 | $this->certpass = $certpass; | ||
1945 | 979 | } | ||
1946 | 980 | |||
1947 | 981 | /** | ||
1948 | 982 | * Add a CA certificate to verify server with (see man page about | ||
1949 | 983 | * CURLOPT_CAINFO for more details | ||
1950 | 984 | * @param string $cacert certificate file name (or dir holding certificates) | ||
1951 | 985 | * @param bool $is_dir set to true to indicate cacert is a dir. defaults to false | ||
1952 | 986 | * @access public | ||
1953 | 987 | */ | ||
1954 | 988 | function setCaCertificate($cacert, $is_dir=false) | ||
1955 | 989 | { | ||
1956 | 990 | if ($is_dir) | ||
1957 | 991 | { | ||
1958 | 992 | $this->cacertdir = $cacert; | ||
1959 | 993 | } | ||
1960 | 994 | else | ||
1961 | 995 | { | ||
1962 | 996 | $this->cacert = $cacert; | ||
1963 | 997 | } | ||
1964 | 998 | } | ||
1965 | 999 | |||
1966 | 1000 | /** | ||
1967 | 1001 | * Set attributes for SSL communication: private SSL key | ||
1968 | 1002 | * NB: does not work in older php/curl installs | ||
1969 | 1003 | * Thanks to Daniel Convissor | ||
1970 | 1004 | * @param string $key The name of a file containing a private SSL key | ||
1971 | 1005 | * @param string $keypass The secret password needed to use the private SSL key | ||
1972 | 1006 | * @access public | ||
1973 | 1007 | */ | ||
1974 | 1008 | function setKey($key, $keypass) | ||
1975 | 1009 | { | ||
1976 | 1010 | $this->key = $key; | ||
1977 | 1011 | $this->keypass = $keypass; | ||
1978 | 1012 | } | ||
1979 | 1013 | |||
1980 | 1014 | /** | ||
1981 | 1015 | * Set attributes for SSL communication: verify server certificate | ||
1982 | 1016 | * @param bool $i enable/disable verification of peer certificate | ||
1983 | 1017 | * @access public | ||
1984 | 1018 | */ | ||
1985 | 1019 | function setSSLVerifyPeer($i) | ||
1986 | 1020 | { | ||
1987 | 1021 | $this->verifypeer = $i; | ||
1988 | 1022 | } | ||
1989 | 1023 | |||
1990 | 1024 | /** | ||
1991 | 1025 | * Set attributes for SSL communication: verify match of server cert w. hostname | ||
1992 | 1026 | * @param int $i | ||
1993 | 1027 | * @access public | ||
1994 | 1028 | */ | ||
1995 | 1029 | function setSSLVerifyHost($i) | ||
1996 | 1030 | { | ||
1997 | 1031 | $this->verifyhost = $i; | ||
1998 | 1032 | } | ||
1999 | 1033 | |||
2000 | 1034 | /** | ||
2001 | 1035 | * Set proxy info | ||
2002 | 1036 | * @param string $proxyhost | ||
2003 | 1037 | * @param string $proxyport Defaults to 8080 for HTTP and 443 for HTTPS | ||
2004 | 1038 | * @param string $proxyusername Leave blank if proxy has public access | ||
2005 | 1039 | * @param string $proxypassword Leave blank if proxy has public access | ||
2006 | 1040 | * @param int $proxyauthtype set to constant CURLAUTH_NTLM to use NTLM auth with proxy | ||
2007 | 1041 | * @access public | ||
2008 | 1042 | */ | ||
2009 | 1043 | function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 1) | ||
2010 | 1044 | { | ||
2011 | 1045 | $this->proxy = $proxyhost; | ||
2012 | 1046 | $this->proxyport = $proxyport; | ||
2013 | 1047 | $this->proxy_user = $proxyusername; | ||
2014 | 1048 | $this->proxy_pass = $proxypassword; | ||
2015 | 1049 | $this->proxy_authtype = $proxyauthtype; | ||
2016 | 1050 | } | ||
2017 | 1051 | |||
2018 | 1052 | /** | ||
2019 | 1053 | * Enables/disables reception of compressed xmlrpc responses. | ||
2020 | 1054 | * Note that enabling reception of compressed responses merely adds some standard | ||
2021 | 1055 | * http headers to xmlrpc requests. It is up to the xmlrpc server to return | ||
2022 | 1056 | * compressed responses when receiving such requests. | ||
2023 | 1057 | * @param string $compmethod either 'gzip', 'deflate', 'any' or '' | ||
2024 | 1058 | * @access public | ||
2025 | 1059 | */ | ||
2026 | 1060 | function setAcceptedCompression($compmethod) | ||
2027 | 1061 | { | ||
2028 | 1062 | if ($compmethod == 'any') | ||
2029 | 1063 | $this->accepted_compression = array('gzip', 'deflate'); | ||
2030 | 1064 | else | ||
2031 | 1065 | $this->accepted_compression = array($compmethod); | ||
2032 | 1066 | } | ||
2033 | 1067 | |||
2034 | 1068 | /** | ||
2035 | 1069 | * Enables/disables http compression of xmlrpc request. | ||
2036 | 1070 | * Take care when sending compressed requests: servers might not support them | ||
2037 | 1071 | * (and automatic fallback to uncompressed requests is not yet implemented) | ||
2038 | 1072 | * @param string $compmethod either 'gzip', 'deflate' or '' | ||
2039 | 1073 | * @access public | ||
2040 | 1074 | */ | ||
2041 | 1075 | function setRequestCompression($compmethod) | ||
2042 | 1076 | { | ||
2043 | 1077 | $this->request_compression = $compmethod; | ||
2044 | 1078 | } | ||
2045 | 1079 | |||
2046 | 1080 | /** | ||
2047 | 1081 | * Adds a cookie to list of cookies that will be sent to server. | ||
2048 | 1082 | * NB: setting any param but name and value will turn the cookie into a 'version 1' cookie: | ||
2049 | 1083 | * do not do it unless you know what you are doing | ||
2050 | 1084 | * @param string $name | ||
2051 | 1085 | * @param string $value | ||
2052 | 1086 | * @param string $path | ||
2053 | 1087 | * @param string $domain | ||
2054 | 1088 | * @param int $port | ||
2055 | 1089 | * @access public | ||
2056 | 1090 | * | ||
2057 | 1091 | * @todo check correctness of urlencoding cookie value (copied from php way of doing it...) | ||
2058 | 1092 | */ | ||
2059 | 1093 | function setCookie($name, $value='', $path='', $domain='', $port=null) | ||
2060 | 1094 | { | ||
2061 | 1095 | $this->cookies[$name]['value'] = urlencode($value); | ||
2062 | 1096 | if ($path || $domain || $port) | ||
2063 | 1097 | { | ||
2064 | 1098 | $this->cookies[$name]['path'] = $path; | ||
2065 | 1099 | $this->cookies[$name]['domain'] = $domain; | ||
2066 | 1100 | $this->cookies[$name]['port'] = $port; | ||
2067 | 1101 | $this->cookies[$name]['version'] = 1; | ||
2068 | 1102 | } | ||
2069 | 1103 | else | ||
2070 | 1104 | { | ||
2071 | 1105 | $this->cookies[$name]['version'] = 0; | ||
2072 | 1106 | } | ||
2073 | 1107 | } | ||
2074 | 1108 | |||
2075 | 1109 | /** | ||
2076 | 1110 | * Directly set cURL options, for extra flexibility | ||
2077 | 1111 | * It allows eg. to bind client to a specific IP interface / address | ||
2078 | 1112 | * @param $options array | ||
2079 | 1113 | */ | ||
2080 | 1114 | function SetCurlOptions( $options ) | ||
2081 | 1115 | { | ||
2082 | 1116 | $this->extracurlopts = $options; | ||
2083 | 1117 | } | ||
2084 | 1118 | |||
2085 | 1119 | /** | ||
2086 | 1120 | * Set user-agent string that will be used by this client instance | ||
2087 | 1121 | * in http headers sent to the server | ||
2088 | 1122 | */ | ||
2089 | 1123 | function SetUserAgent( $agentstring ) | ||
2090 | 1124 | { | ||
2091 | 1125 | $this->user_agent = $agentstring; | ||
2092 | 1126 | } | ||
2093 | 1127 | |||
2094 | 1128 | /** | ||
2095 | 1129 | * Send an xmlrpc request | ||
2096 | 1130 | * @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request | ||
2097 | 1131 | * @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply | ||
2098 | 1132 | * @param string $method if left unspecified, the http protocol chosen during creation of the object will be used | ||
2099 | 1133 | * @return xmlrpcresp | ||
2100 | 1134 | * @access public | ||
2101 | 1135 | */ | ||
2102 | 1136 | function& send($msg, $timeout=0, $method='') | ||
2103 | 1137 | { | ||
2104 | 1138 | // if user deos not specify http protocol, use native method of this client | ||
2105 | 1139 | // (i.e. method set during call to constructor) | ||
2106 | 1140 | if($method == '') | ||
2107 | 1141 | { | ||
2108 | 1142 | $method = $this->method; | ||
2109 | 1143 | } | ||
2110 | 1144 | |||
2111 | 1145 | if(is_array($msg)) | ||
2112 | 1146 | { | ||
2113 | 1147 | // $msg is an array of xmlrpcmsg's | ||
2114 | 1148 | $r = $this->multicall($msg, $timeout, $method); | ||
2115 | 1149 | return $r; | ||
2116 | 1150 | } | ||
2117 | 1151 | elseif(is_string($msg)) | ||
2118 | 1152 | { | ||
2119 | 1153 | $n = new xmlrpcmsg(''); | ||
2120 | 1154 | $n->payload = $msg; | ||
2121 | 1155 | $msg = $n; | ||
2122 | 1156 | } | ||
2123 | 1157 | |||
2124 | 1158 | // where msg is an xmlrpcmsg | ||
2125 | 1159 | $msg->debug=$this->debug; | ||
2126 | 1160 | |||
2127 | 1161 | if($method == 'https') | ||
2128 | 1162 | { | ||
2129 | 1163 | $r =& $this->sendPayloadHTTPS( | ||
2130 | 1164 | $msg, | ||
2131 | 1165 | $this->server, | ||
2132 | 1166 | $this->port, | ||
2133 | 1167 | $timeout, | ||
2134 | 1168 | $this->username, | ||
2135 | 1169 | $this->password, | ||
2136 | 1170 | $this->authtype, | ||
2137 | 1171 | $this->cert, | ||
2138 | 1172 | $this->certpass, | ||
2139 | 1173 | $this->cacert, | ||
2140 | 1174 | $this->cacertdir, | ||
2141 | 1175 | $this->proxy, | ||
2142 | 1176 | $this->proxyport, | ||
2143 | 1177 | $this->proxy_user, | ||
2144 | 1178 | $this->proxy_pass, | ||
2145 | 1179 | $this->proxy_authtype, | ||
2146 | 1180 | $this->keepalive, | ||
2147 | 1181 | $this->key, | ||
2148 | 1182 | $this->keypass | ||
2149 | 1183 | ); | ||
2150 | 1184 | } | ||
2151 | 1185 | elseif($method == 'http11') | ||
2152 | 1186 | { | ||
2153 | 1187 | $r =& $this->sendPayloadCURL( | ||
2154 | 1188 | $msg, | ||
2155 | 1189 | $this->server, | ||
2156 | 1190 | $this->port, | ||
2157 | 1191 | $timeout, | ||
2158 | 1192 | $this->username, | ||
2159 | 1193 | $this->password, | ||
2160 | 1194 | $this->authtype, | ||
2161 | 1195 | null, | ||
2162 | 1196 | null, | ||
2163 | 1197 | null, | ||
2164 | 1198 | null, | ||
2165 | 1199 | $this->proxy, | ||
2166 | 1200 | $this->proxyport, | ||
2167 | 1201 | $this->proxy_user, | ||
2168 | 1202 | $this->proxy_pass, | ||
2169 | 1203 | $this->proxy_authtype, | ||
2170 | 1204 | 'http', | ||
2171 | 1205 | $this->keepalive | ||
2172 | 1206 | ); | ||
2173 | 1207 | } | ||
2174 | 1208 | else | ||
2175 | 1209 | { | ||
2176 | 1210 | $r =& $this->sendPayloadHTTP10( | ||
2177 | 1211 | $msg, | ||
2178 | 1212 | $this->server, | ||
2179 | 1213 | $this->port, | ||
2180 | 1214 | $timeout, | ||
2181 | 1215 | $this->username, | ||
2182 | 1216 | $this->password, | ||
2183 | 1217 | $this->authtype, | ||
2184 | 1218 | $this->proxy, | ||
2185 | 1219 | $this->proxyport, | ||
2186 | 1220 | $this->proxy_user, | ||
2187 | 1221 | $this->proxy_pass, | ||
2188 | 1222 | $this->proxy_authtype | ||
2189 | 1223 | ); | ||
2190 | 1224 | } | ||
2191 | 1225 | |||
2192 | 1226 | return $r; | ||
2193 | 1227 | } | ||
2194 | 1228 | |||
2195 | 1229 | /** | ||
2196 | 1230 | * @access private | ||
2197 | 1231 | */ | ||
2198 | 1232 | function &sendPayloadHTTP10($msg, $server, $port, $timeout=0, | ||
2199 | 1233 | $username='', $password='', $authtype=1, $proxyhost='', | ||
2200 | 1234 | $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1) | ||
2201 | 1235 | { | ||
2202 | 1236 | if($port==0) | ||
2203 | 1237 | { | ||
2204 | 1238 | $port=80; | ||
2205 | 1239 | } | ||
2206 | 1240 | |||
2207 | 1241 | // Only create the payload if it was not created previously | ||
2208 | 1242 | if(empty($msg->payload)) | ||
2209 | 1243 | { | ||
2210 | 1244 | $msg->createPayload($this->request_charset_encoding); | ||
2211 | 1245 | } | ||
2212 | 1246 | |||
2213 | 1247 | $payload = $msg->payload; | ||
2214 | 1248 | // Deflate request body and set appropriate request headers | ||
2215 | 1249 | if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate')) | ||
2216 | 1250 | { | ||
2217 | 1251 | if($this->request_compression == 'gzip') | ||
2218 | 1252 | { | ||
2219 | 1253 | $a = @gzencode($payload); | ||
2220 | 1254 | if($a) | ||
2221 | 1255 | { | ||
2222 | 1256 | $payload = $a; | ||
2223 | 1257 | $encoding_hdr = "Content-Encoding: gzip\r\n"; | ||
2224 | 1258 | } | ||
2225 | 1259 | } | ||
2226 | 1260 | else | ||
2227 | 1261 | { | ||
2228 | 1262 | $a = @gzcompress($payload); | ||
2229 | 1263 | if($a) | ||
2230 | 1264 | { | ||
2231 | 1265 | $payload = $a; | ||
2232 | 1266 | $encoding_hdr = "Content-Encoding: deflate\r\n"; | ||
2233 | 1267 | } | ||
2234 | 1268 | } | ||
2235 | 1269 | } | ||
2236 | 1270 | else | ||
2237 | 1271 | { | ||
2238 | 1272 | $encoding_hdr = ''; | ||
2239 | 1273 | } | ||
2240 | 1274 | |||
2241 | 1275 | // thanks to Grant Rauscher <grant7@firstworld.net> for this | ||
2242 | 1276 | $credentials=''; | ||
2243 | 1277 | if($username!='') | ||
2244 | 1278 | { | ||
2245 | 1279 | $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; | ||
2246 | 1280 | if ($authtype != 1) | ||
2247 | 1281 | { | ||
2248 | 1282 | error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported with HTTP 1.0'); | ||
2249 | 1283 | } | ||
2250 | 1284 | } | ||
2251 | 1285 | |||
2252 | 1286 | $accepted_encoding = ''; | ||
2253 | 1287 | if(is_array($this->accepted_compression) && count($this->accepted_compression)) | ||
2254 | 1288 | { | ||
2255 | 1289 | $accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n"; | ||
2256 | 1290 | } | ||
2257 | 1291 | |||
2258 | 1292 | $proxy_credentials = ''; | ||
2259 | 1293 | if($proxyhost) | ||
2260 | 1294 | { | ||
2261 | 1295 | if($proxyport == 0) | ||
2262 | 1296 | { | ||
2263 | 1297 | $proxyport = 8080; | ||
2264 | 1298 | } | ||
2265 | 1299 | $connectserver = $proxyhost; | ||
2266 | 1300 | $connectport = $proxyport; | ||
2267 | 1301 | $uri = 'http://'.$server.':'.$port.$this->path; | ||
2268 | 1302 | if($proxyusername != '') | ||
2269 | 1303 | { | ||
2270 | 1304 | if ($proxyauthtype != 1) | ||
2271 | 1305 | { | ||
2272 | 1306 | error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported with HTTP 1.0'); | ||
2273 | 1307 | } | ||
2274 | 1308 | $proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n"; | ||
2275 | 1309 | } | ||
2276 | 1310 | } | ||
2277 | 1311 | else | ||
2278 | 1312 | { | ||
2279 | 1313 | $connectserver = $server; | ||
2280 | 1314 | $connectport = $port; | ||
2281 | 1315 | $uri = $this->path; | ||
2282 | 1316 | } | ||
2283 | 1317 | |||
2284 | 1318 | // Cookie generation, as per rfc2965 (version 1 cookies) or | ||
2285 | 1319 | // netscape's rules (version 0 cookies) | ||
2286 | 1320 | $cookieheader=''; | ||
2287 | 1321 | if (count($this->cookies)) | ||
2288 | 1322 | { | ||
2289 | 1323 | $version = ''; | ||
2290 | 1324 | foreach ($this->cookies as $name => $cookie) | ||
2291 | 1325 | { | ||
2292 | 1326 | if ($cookie['version']) | ||
2293 | 1327 | { | ||
2294 | 1328 | $version = ' $Version="' . $cookie['version'] . '";'; | ||
2295 | 1329 | $cookieheader .= ' ' . $name . '="' . $cookie['value'] . '";'; | ||
2296 | 1330 | if ($cookie['path']) | ||
2297 | 1331 | $cookieheader .= ' $Path="' . $cookie['path'] . '";'; | ||
2298 | 1332 | if ($cookie['domain']) | ||
2299 | 1333 | $cookieheader .= ' $Domain="' . $cookie['domain'] . '";'; | ||
2300 | 1334 | if ($cookie['port']) | ||
2301 | 1335 | $cookieheader .= ' $Port="' . $cookie['port'] . '";'; | ||
2302 | 1336 | } | ||
2303 | 1337 | else | ||
2304 | 1338 | { | ||
2305 | 1339 | $cookieheader .= ' ' . $name . '=' . $cookie['value'] . ";"; | ||
2306 | 1340 | } | ||
2307 | 1341 | } | ||
2308 | 1342 | $cookieheader = 'Cookie:' . $version . substr($cookieheader, 0, -1) . "\r\n"; | ||
2309 | 1343 | } | ||
2310 | 1344 | |||
2311 | 1345 | $op= 'POST ' . $uri. " HTTP/1.0\r\n" . | ||
2312 | 1346 | 'User-Agent: ' . $this->user_agent . "\r\n" . | ||
2313 | 1347 | 'Host: '. $server . ':' . $port . "\r\n" . | ||
2314 | 1348 | $credentials . | ||
2315 | 1349 | $proxy_credentials . | ||
2316 | 1350 | $accepted_encoding . | ||
2317 | 1351 | $encoding_hdr . | ||
2318 | 1352 | 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings) . "\r\n" . | ||
2319 | 1353 | $cookieheader . | ||
2320 | 1354 | 'Content-Type: ' . $msg->content_type . "\r\nContent-Length: " . | ||
2321 | 1355 | strlen($payload) . "\r\n\r\n" . | ||
2322 | 1356 | $payload; | ||
2323 | 1357 | |||
2324 | 1358 | if($this->debug > 1) | ||
2325 | 1359 | { | ||
2326 | 1360 | print "<PRE>\n---SENDING---\n" . htmlentities($op) . "\n---END---\n</PRE>"; | ||
2327 | 1361 | // let the client see this now in case http times out... | ||
2328 | 1362 | flush(); | ||
2329 | 1363 | } | ||
2330 | 1364 | |||
2331 | 1365 | if($timeout>0) | ||
2332 | 1366 | { | ||
2333 | 1367 | $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout); | ||
2334 | 1368 | } | ||
2335 | 1369 | else | ||
2336 | 1370 | { | ||
2337 | 1371 | $fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr); | ||
2338 | 1372 | } | ||
2339 | 1373 | if($fp) | ||
2340 | 1374 | { | ||
2341 | 1375 | if($timeout>0 && function_exists('stream_set_timeout')) | ||
2342 | 1376 | { | ||
2343 | 1377 | stream_set_timeout($fp, $timeout); | ||
2344 | 1378 | } | ||
2345 | 1379 | } | ||
2346 | 1380 | else | ||
2347 | 1381 | { | ||
2348 | 1382 | $this->errstr='Connect error: '.$this->errstr; | ||
2349 | 1383 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')'); | ||
2350 | 1384 | return $r; | ||
2351 | 1385 | } | ||
2352 | 1386 | |||
2353 | 1387 | if(!fputs($fp, $op, strlen($op))) | ||
2354 | 1388 | { | ||
2355 | 1389 | fclose($fp); | ||
2356 | 1390 | $this->errstr='Write error'; | ||
2357 | 1391 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr); | ||
2358 | 1392 | return $r; | ||
2359 | 1393 | } | ||
2360 | 1394 | else | ||
2361 | 1395 | { | ||
2362 | 1396 | // reset errno and errstr on succesful socket connection | ||
2363 | 1397 | $this->errstr = ''; | ||
2364 | 1398 | } | ||
2365 | 1399 | // G. Giunta 2005/10/24: close socket before parsing. | ||
2366 | 1400 | // should yeld slightly better execution times, and make easier recursive calls (e.g. to follow http redirects) | ||
2367 | 1401 | $ipd=''; | ||
2368 | 1402 | do | ||
2369 | 1403 | { | ||
2370 | 1404 | // shall we check for $data === FALSE? | ||
2371 | 1405 | // as per the manual, it signals an error | ||
2372 | 1406 | $ipd.=fread($fp, 32768); | ||
2373 | 1407 | } while(!feof($fp)); | ||
2374 | 1408 | fclose($fp); | ||
2375 | 1409 | $r =& $msg->parseResponse($ipd, false, $this->return_type); | ||
2376 | 1410 | return $r; | ||
2377 | 1411 | |||
2378 | 1412 | } | ||
2379 | 1413 | |||
2380 | 1414 | /** | ||
2381 | 1415 | * @access private | ||
2382 | 1416 | */ | ||
2383 | 1417 | function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='', | ||
2384 | 1418 | $password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='', | ||
2385 | 1419 | $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, | ||
2386 | 1420 | $keepalive=false, $key='', $keypass='') | ||
2387 | 1421 | { | ||
2388 | 1422 | $r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username, | ||
2389 | 1423 | $password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport, | ||
2390 | 1424 | $proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass); | ||
2391 | 1425 | return $r; | ||
2392 | 1426 | } | ||
2393 | 1427 | |||
2394 | 1428 | /** | ||
2395 | 1429 | * Contributed by Justin Miller <justin@voxel.net> | ||
2396 | 1430 | * Requires curl to be built into PHP | ||
2397 | 1431 | * NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers! | ||
2398 | 1432 | * @access private | ||
2399 | 1433 | */ | ||
2400 | 1434 | function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='', | ||
2401 | 1435 | $password='', $authtype=1, $cert='', $certpass='', $cacert='', $cacertdir='', | ||
2402 | 1436 | $proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $method='https', | ||
2403 | 1437 | $keepalive=false, $key='', $keypass='') | ||
2404 | 1438 | { | ||
2405 | 1439 | if(!function_exists('curl_init')) | ||
2406 | 1440 | { | ||
2407 | 1441 | $this->errstr='CURL unavailable on this install'; | ||
2408 | 1442 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']); | ||
2409 | 1443 | return $r; | ||
2410 | 1444 | } | ||
2411 | 1445 | if($method == 'https') | ||
2412 | 1446 | { | ||
2413 | 1447 | if(($info = curl_version()) && | ||
2414 | 1448 | ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version'])))) | ||
2415 | 1449 | { | ||
2416 | 1450 | $this->errstr='SSL unavailable on this install'; | ||
2417 | 1451 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']); | ||
2418 | 1452 | return $r; | ||
2419 | 1453 | } | ||
2420 | 1454 | } | ||
2421 | 1455 | |||
2422 | 1456 | if($port == 0) | ||
2423 | 1457 | { | ||
2424 | 1458 | if($method == 'http') | ||
2425 | 1459 | { | ||
2426 | 1460 | $port = 80; | ||
2427 | 1461 | } | ||
2428 | 1462 | else | ||
2429 | 1463 | { | ||
2430 | 1464 | $port = 443; | ||
2431 | 1465 | } | ||
2432 | 1466 | } | ||
2433 | 1467 | |||
2434 | 1468 | // Only create the payload if it was not created previously | ||
2435 | 1469 | if(empty($msg->payload)) | ||
2436 | 1470 | { | ||
2437 | 1471 | $msg->createPayload($this->request_charset_encoding); | ||
2438 | 1472 | } | ||
2439 | 1473 | |||
2440 | 1474 | // Deflate request body and set appropriate request headers | ||
2441 | 1475 | $payload = $msg->payload; | ||
2442 | 1476 | if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate')) | ||
2443 | 1477 | { | ||
2444 | 1478 | if($this->request_compression == 'gzip') | ||
2445 | 1479 | { | ||
2446 | 1480 | $a = @gzencode($payload); | ||
2447 | 1481 | if($a) | ||
2448 | 1482 | { | ||
2449 | 1483 | $payload = $a; | ||
2450 | 1484 | $encoding_hdr = 'Content-Encoding: gzip'; | ||
2451 | 1485 | } | ||
2452 | 1486 | } | ||
2453 | 1487 | else | ||
2454 | 1488 | { | ||
2455 | 1489 | $a = @gzcompress($payload); | ||
2456 | 1490 | if($a) | ||
2457 | 1491 | { | ||
2458 | 1492 | $payload = $a; | ||
2459 | 1493 | $encoding_hdr = 'Content-Encoding: deflate'; | ||
2460 | 1494 | } | ||
2461 | 1495 | } | ||
2462 | 1496 | } | ||
2463 | 1497 | else | ||
2464 | 1498 | { | ||
2465 | 1499 | $encoding_hdr = ''; | ||
2466 | 1500 | } | ||
2467 | 1501 | |||
2468 | 1502 | if($this->debug > 1) | ||
2469 | 1503 | { | ||
2470 | 1504 | print "<PRE>\n---SENDING---\n" . htmlentities($payload) . "\n---END---\n</PRE>"; | ||
2471 | 1505 | // let the client see this now in case http times out... | ||
2472 | 1506 | flush(); | ||
2473 | 1507 | } | ||
2474 | 1508 | |||
2475 | 1509 | if(!$keepalive || !$this->xmlrpc_curl_handle) | ||
2476 | 1510 | { | ||
2477 | 1511 | $curl = curl_init($method . '://' . $server . ':' . $port . $this->path); | ||
2478 | 1512 | if($keepalive) | ||
2479 | 1513 | { | ||
2480 | 1514 | $this->xmlrpc_curl_handle = $curl; | ||
2481 | 1515 | } | ||
2482 | 1516 | } | ||
2483 | 1517 | else | ||
2484 | 1518 | { | ||
2485 | 1519 | $curl = $this->xmlrpc_curl_handle; | ||
2486 | 1520 | } | ||
2487 | 1521 | |||
2488 | 1522 | // results into variable | ||
2489 | 1523 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); | ||
2490 | 1524 | |||
2491 | 1525 | if($this->debug) | ||
2492 | 1526 | { | ||
2493 | 1527 | curl_setopt($curl, CURLOPT_VERBOSE, 1); | ||
2494 | 1528 | } | ||
2495 | 1529 | curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent); | ||
2496 | 1530 | // required for XMLRPC: post the data | ||
2497 | 1531 | curl_setopt($curl, CURLOPT_POST, 1); | ||
2498 | 1532 | // the data | ||
2499 | 1533 | curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); | ||
2500 | 1534 | |||
2501 | 1535 | // return the header too | ||
2502 | 1536 | curl_setopt($curl, CURLOPT_HEADER, 1); | ||
2503 | 1537 | |||
2504 | 1538 | // will only work with PHP >= 5.0 | ||
2505 | 1539 | // NB: if we set an empty string, CURL will add http header indicating | ||
2506 | 1540 | // ALL methods it is supporting. This is possibly a better option than | ||
2507 | 1541 | // letting the user tell what curl can / cannot do... | ||
2508 | 1542 | if(is_array($this->accepted_compression) && count($this->accepted_compression)) | ||
2509 | 1543 | { | ||
2510 | 1544 | //curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression)); | ||
2511 | 1545 | // empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?) | ||
2512 | 1546 | if (count($this->accepted_compression) == 1) | ||
2513 | 1547 | { | ||
2514 | 1548 | curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]); | ||
2515 | 1549 | } | ||
2516 | 1550 | else | ||
2517 | 1551 | curl_setopt($curl, CURLOPT_ENCODING, ''); | ||
2518 | 1552 | } | ||
2519 | 1553 | // extra headers | ||
2520 | 1554 | $headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings)); | ||
2521 | 1555 | // if no keepalive is wanted, let the server know it in advance | ||
2522 | 1556 | if(!$keepalive) | ||
2523 | 1557 | { | ||
2524 | 1558 | $headers[] = 'Connection: close'; | ||
2525 | 1559 | } | ||
2526 | 1560 | // request compression header | ||
2527 | 1561 | if($encoding_hdr) | ||
2528 | 1562 | { | ||
2529 | 1563 | $headers[] = $encoding_hdr; | ||
2530 | 1564 | } | ||
2531 | 1565 | |||
2532 | 1566 | curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); | ||
2533 | 1567 | // timeout is borked | ||
2534 | 1568 | if($timeout) | ||
2535 | 1569 | { | ||
2536 | 1570 | curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1); | ||
2537 | 1571 | } | ||
2538 | 1572 | |||
2539 | 1573 | if($username && $password) | ||
2540 | 1574 | { | ||
2541 | 1575 | curl_setopt($curl, CURLOPT_USERPWD, $username.':'.$password); | ||
2542 | 1576 | if (defined('CURLOPT_HTTPAUTH')) | ||
2543 | 1577 | { | ||
2544 | 1578 | curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype); | ||
2545 | 1579 | } | ||
2546 | 1580 | else if ($authtype != 1) | ||
2547 | 1581 | { | ||
2548 | 1582 | error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported by the current PHP/curl install'); | ||
2549 | 1583 | } | ||
2550 | 1584 | } | ||
2551 | 1585 | |||
2552 | 1586 | if($method == 'https') | ||
2553 | 1587 | { | ||
2554 | 1588 | // set cert file | ||
2555 | 1589 | if($cert) | ||
2556 | 1590 | { | ||
2557 | 1591 | curl_setopt($curl, CURLOPT_SSLCERT, $cert); | ||
2558 | 1592 | } | ||
2559 | 1593 | // set cert password | ||
2560 | 1594 | if($certpass) | ||
2561 | 1595 | { | ||
2562 | 1596 | curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass); | ||
2563 | 1597 | } | ||
2564 | 1598 | // whether to verify remote host's cert | ||
2565 | 1599 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer); | ||
2566 | 1600 | // set ca certificates file/dir | ||
2567 | 1601 | if($cacert) | ||
2568 | 1602 | { | ||
2569 | 1603 | curl_setopt($curl, CURLOPT_CAINFO, $cacert); | ||
2570 | 1604 | } | ||
2571 | 1605 | if($cacertdir) | ||
2572 | 1606 | { | ||
2573 | 1607 | curl_setopt($curl, CURLOPT_CAPATH, $cacertdir); | ||
2574 | 1608 | } | ||
2575 | 1609 | // set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?) | ||
2576 | 1610 | if($key) | ||
2577 | 1611 | { | ||
2578 | 1612 | curl_setopt($curl, CURLOPT_SSLKEY, $key); | ||
2579 | 1613 | } | ||
2580 | 1614 | // set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?) | ||
2581 | 1615 | if($keypass) | ||
2582 | 1616 | { | ||
2583 | 1617 | curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass); | ||
2584 | 1618 | } | ||
2585 | 1619 | // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used | ||
2586 | 1620 | curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost); | ||
2587 | 1621 | } | ||
2588 | 1622 | |||
2589 | 1623 | // proxy info | ||
2590 | 1624 | if($proxyhost) | ||
2591 | 1625 | { | ||
2592 | 1626 | if($proxyport == 0) | ||
2593 | 1627 | { | ||
2594 | 1628 | $proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080 | ||
2595 | 1629 | } | ||
2596 | 1630 | curl_setopt($curl, CURLOPT_PROXY, $proxyhost.':'.$proxyport); | ||
2597 | 1631 | //curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport); | ||
2598 | 1632 | if($proxyusername) | ||
2599 | 1633 | { | ||
2600 | 1634 | curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword); | ||
2601 | 1635 | if (defined('CURLOPT_PROXYAUTH')) | ||
2602 | 1636 | { | ||
2603 | 1637 | curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype); | ||
2604 | 1638 | } | ||
2605 | 1639 | else if ($proxyauthtype != 1) | ||
2606 | 1640 | { | ||
2607 | 1641 | error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); | ||
2608 | 1642 | } | ||
2609 | 1643 | } | ||
2610 | 1644 | } | ||
2611 | 1645 | |||
2612 | 1646 | // NB: should we build cookie http headers by hand rather than let CURL do it? | ||
2613 | 1647 | // the following code does not honour 'expires', 'path' and 'domain' cookie attributes | ||
2614 | 1648 | // set to client obj the the user... | ||
2615 | 1649 | if (count($this->cookies)) | ||
2616 | 1650 | { | ||
2617 | 1651 | $cookieheader = ''; | ||
2618 | 1652 | foreach ($this->cookies as $name => $cookie) | ||
2619 | 1653 | { | ||
2620 | 1654 | $cookieheader .= $name . '=' . $cookie['value'] . '; '; | ||
2621 | 1655 | } | ||
2622 | 1656 | curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2)); | ||
2623 | 1657 | } | ||
2624 | 1658 | |||
2625 | 1659 | foreach ($this->extracurlopts as $opt => $val) | ||
2626 | 1660 | { | ||
2627 | 1661 | curl_setopt($curl, $opt, $val); | ||
2628 | 1662 | } | ||
2629 | 1663 | |||
2630 | 1664 | $result = curl_exec($curl); | ||
2631 | 1665 | |||
2632 | 1666 | if ($this->debug > 1) | ||
2633 | 1667 | { | ||
2634 | 1668 | print "<PRE>\n---CURL INFO---\n"; | ||
2635 | 1669 | foreach(curl_getinfo($curl) as $name => $val) | ||
2636 | 1670 | print $name . ': ' . htmlentities($val). "\n"; | ||
2637 | 1671 | print "---END---\n</PRE>"; | ||
2638 | 1672 | } | ||
2639 | 1673 | |||
2640 | 1674 | if(!$result) /// @todo we should use a better check here - what if we get back '' or '0'? | ||
2641 | 1675 | { | ||
2642 | 1676 | $this->errstr='no response'; | ||
2643 | 1677 | $resp=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl)); | ||
2644 | 1678 | curl_close($curl); | ||
2645 | 1679 | if($keepalive) | ||
2646 | 1680 | { | ||
2647 | 1681 | $this->xmlrpc_curl_handle = null; | ||
2648 | 1682 | } | ||
2649 | 1683 | } | ||
2650 | 1684 | else | ||
2651 | 1685 | { | ||
2652 | 1686 | if(!$keepalive) | ||
2653 | 1687 | { | ||
2654 | 1688 | curl_close($curl); | ||
2655 | 1689 | } | ||
2656 | 1690 | $resp =& $msg->parseResponse($result, true, $this->return_type); | ||
2657 | 1691 | } | ||
2658 | 1692 | return $resp; | ||
2659 | 1693 | } | ||
2660 | 1694 | |||
2661 | 1695 | /** | ||
2662 | 1696 | * Send an array of request messages and return an array of responses. | ||
2663 | 1697 | * Unless $this->no_multicall has been set to true, it will try first | ||
2664 | 1698 | * to use one single xmlrpc call to server method system.multicall, and | ||
2665 | 1699 | * revert to sending many successive calls in case of failure. | ||
2666 | 1700 | * This failure is also stored in $this->no_multicall for subsequent calls. | ||
2667 | 1701 | * Unfortunately, there is no server error code universally used to denote | ||
2668 | 1702 | * the fact that multicall is unsupported, so there is no way to reliably | ||
2669 | 1703 | * distinguish between that and a temporary failure. | ||
2670 | 1704 | * If you are sure that server supports multicall and do not want to | ||
2671 | 1705 | * fallback to using many single calls, set the fourth parameter to FALSE. | ||
2672 | 1706 | * | ||
2673 | 1707 | * NB: trying to shoehorn extra functionality into existing syntax has resulted | ||
2674 | 1708 | * in pretty much convoluted code... | ||
2675 | 1709 | * | ||
2676 | 1710 | * @param array $msgs an array of xmlrpcmsg objects | ||
2677 | 1711 | * @param integer $timeout connection timeout (in seconds) | ||
2678 | 1712 | * @param string $method the http protocol variant to be used | ||
2679 | 1713 | * @param boolean fallback When true, upon receiveing an error during multicall, multiple single calls will be attempted | ||
2680 | 1714 | * @return array | ||
2681 | 1715 | * @access public | ||
2682 | 1716 | */ | ||
2683 | 1717 | function multicall($msgs, $timeout=0, $method='', $fallback=true) | ||
2684 | 1718 | { | ||
2685 | 1719 | if ($method == '') | ||
2686 | 1720 | { | ||
2687 | 1721 | $method = $this->method; | ||
2688 | 1722 | } | ||
2689 | 1723 | if(!$this->no_multicall) | ||
2690 | 1724 | { | ||
2691 | 1725 | $results = $this->_try_multicall($msgs, $timeout, $method); | ||
2692 | 1726 | if(is_array($results)) | ||
2693 | 1727 | { | ||
2694 | 1728 | // System.multicall succeeded | ||
2695 | 1729 | return $results; | ||
2696 | 1730 | } | ||
2697 | 1731 | else | ||
2698 | 1732 | { | ||
2699 | 1733 | // either system.multicall is unsupported by server, | ||
2700 | 1734 | // or call failed for some other reason. | ||
2701 | 1735 | if ($fallback) | ||
2702 | 1736 | { | ||
2703 | 1737 | // Don't try it next time... | ||
2704 | 1738 | $this->no_multicall = true; | ||
2705 | 1739 | } | ||
2706 | 1740 | else | ||
2707 | 1741 | { | ||
2708 | 1742 | if (is_a($results, 'xmlrpcresp')) | ||
2709 | 1743 | { | ||
2710 | 1744 | $result = $results; | ||
2711 | 1745 | } | ||
2712 | 1746 | else | ||
2713 | 1747 | { | ||
2714 | 1748 | $result = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']); | ||
2715 | 1749 | } | ||
2716 | 1750 | } | ||
2717 | 1751 | } | ||
2718 | 1752 | } | ||
2719 | 1753 | else | ||
2720 | 1754 | { | ||
2721 | 1755 | // override fallback, in case careless user tries to do two | ||
2722 | 1756 | // opposite things at the same time | ||
2723 | 1757 | $fallback = true; | ||
2724 | 1758 | } | ||
2725 | 1759 | |||
2726 | 1760 | $results = array(); | ||
2727 | 1761 | if ($fallback) | ||
2728 | 1762 | { | ||
2729 | 1763 | // system.multicall is (probably) unsupported by server: | ||
2730 | 1764 | // emulate multicall via multiple requests | ||
2731 | 1765 | foreach($msgs as $msg) | ||
2732 | 1766 | { | ||
2733 | 1767 | $results[] =& $this->send($msg, $timeout, $method); | ||
2734 | 1768 | } | ||
2735 | 1769 | } | ||
2736 | 1770 | else | ||
2737 | 1771 | { | ||
2738 | 1772 | // user does NOT want to fallback on many single calls: | ||
2739 | 1773 | // since we should always return an array of responses, | ||
2740 | 1774 | // return an array with the same error repeated n times | ||
2741 | 1775 | foreach($msgs as $msg) | ||
2742 | 1776 | { | ||
2743 | 1777 | $results[] = $result; | ||
2744 | 1778 | } | ||
2745 | 1779 | } | ||
2746 | 1780 | return $results; | ||
2747 | 1781 | } | ||
2748 | 1782 | |||
2749 | 1783 | /** | ||
2750 | 1784 | * Attempt to boxcar $msgs via system.multicall. | ||
2751 | 1785 | * Returns either an array of xmlrpcreponses, an xmlrpc error response | ||
2752 | 1786 | * or false (when received response does not respect valid multicall syntax) | ||
2753 | 1787 | * @access private | ||
2754 | 1788 | */ | ||
2755 | 1789 | function _try_multicall($msgs, $timeout, $method) | ||
2756 | 1790 | { | ||
2757 | 1791 | // Construct multicall message | ||
2758 | 1792 | $calls = array(); | ||
2759 | 1793 | foreach($msgs as $msg) | ||
2760 | 1794 | { | ||
2761 | 1795 | $call['methodName'] = new xmlrpcval($msg->method(),'string'); | ||
2762 | 1796 | $numParams = $msg->getNumParams(); | ||
2763 | 1797 | $params = array(); | ||
2764 | 1798 | for($i = 0; $i < $numParams; $i++) | ||
2765 | 1799 | { | ||
2766 | 1800 | $params[$i] = $msg->getParam($i); | ||
2767 | 1801 | } | ||
2768 | 1802 | $call['params'] = new xmlrpcval($params, 'array'); | ||
2769 | 1803 | $calls[] = new xmlrpcval($call, 'struct'); | ||
2770 | 1804 | } | ||
2771 | 1805 | $multicall = new xmlrpcmsg('system.multicall'); | ||
2772 | 1806 | $multicall->addParam(new xmlrpcval($calls, 'array')); | ||
2773 | 1807 | |||
2774 | 1808 | // Attempt RPC call | ||
2775 | 1809 | $result =& $this->send($multicall, $timeout, $method); | ||
2776 | 1810 | |||
2777 | 1811 | if($result->faultCode() != 0) | ||
2778 | 1812 | { | ||
2779 | 1813 | // call to system.multicall failed | ||
2780 | 1814 | return $result; | ||
2781 | 1815 | } | ||
2782 | 1816 | |||
2783 | 1817 | // Unpack responses. | ||
2784 | 1818 | $rets = $result->value(); | ||
2785 | 1819 | |||
2786 | 1820 | if ($this->return_type == 'xml') | ||
2787 | 1821 | { | ||
2788 | 1822 | return $rets; | ||
2789 | 1823 | } | ||
2790 | 1824 | else if ($this->return_type == 'phpvals') | ||
2791 | 1825 | { | ||
2792 | 1826 | ///@todo test this code branch... | ||
2793 | 1827 | $rets = $result->value(); | ||
2794 | 1828 | if(!is_array($rets)) | ||
2795 | 1829 | { | ||
2796 | 1830 | return false; // bad return type from system.multicall | ||
2797 | 1831 | } | ||
2798 | 1832 | $numRets = count($rets); | ||
2799 | 1833 | if($numRets != count($msgs)) | ||
2800 | 1834 | { | ||
2801 | 1835 | return false; // wrong number of return values. | ||
2802 | 1836 | } | ||
2803 | 1837 | |||
2804 | 1838 | $response = array(); | ||
2805 | 1839 | for($i = 0; $i < $numRets; $i++) | ||
2806 | 1840 | { | ||
2807 | 1841 | $val = $rets[$i]; | ||
2808 | 1842 | if (!is_array($val)) { | ||
2809 | 1843 | return false; | ||
2810 | 1844 | } | ||
2811 | 1845 | switch(count($val)) | ||
2812 | 1846 | { | ||
2813 | 1847 | case 1: | ||
2814 | 1848 | if(!isset($val[0])) | ||
2815 | 1849 | { | ||
2816 | 1850 | return false; // Bad value | ||
2817 | 1851 | } | ||
2818 | 1852 | // Normal return value | ||
2819 | 1853 | $response[$i] = new xmlrpcresp($val[0], 0, '', 'phpvals'); | ||
2820 | 1854 | break; | ||
2821 | 1855 | case 2: | ||
2822 | 1856 | /// @todo remove usage of @: it is apparently quite slow | ||
2823 | 1857 | $code = @$val['faultCode']; | ||
2824 | 1858 | if(!is_int($code)) | ||
2825 | 1859 | { | ||
2826 | 1860 | return false; | ||
2827 | 1861 | } | ||
2828 | 1862 | $str = @$val['faultString']; | ||
2829 | 1863 | if(!is_string($str)) | ||
2830 | 1864 | { | ||
2831 | 1865 | return false; | ||
2832 | 1866 | } | ||
2833 | 1867 | $response[$i] = new xmlrpcresp(0, $code, $str); | ||
2834 | 1868 | break; | ||
2835 | 1869 | default: | ||
2836 | 1870 | return false; | ||
2837 | 1871 | } | ||
2838 | 1872 | } | ||
2839 | 1873 | return $response; | ||
2840 | 1874 | } | ||
2841 | 1875 | else // return type == 'xmlrpcvals' | ||
2842 | 1876 | { | ||
2843 | 1877 | $rets = $result->value(); | ||
2844 | 1878 | if($rets->kindOf() != 'array') | ||
2845 | 1879 | { | ||
2846 | 1880 | return false; // bad return type from system.multicall | ||
2847 | 1881 | } | ||
2848 | 1882 | $numRets = $rets->arraysize(); | ||
2849 | 1883 | if($numRets != count($msgs)) | ||
2850 | 1884 | { | ||
2851 | 1885 | return false; // wrong number of return values. | ||
2852 | 1886 | } | ||
2853 | 1887 | |||
2854 | 1888 | $response = array(); | ||
2855 | 1889 | for($i = 0; $i < $numRets; $i++) | ||
2856 | 1890 | { | ||
2857 | 1891 | $val = $rets->arraymem($i); | ||
2858 | 1892 | switch($val->kindOf()) | ||
2859 | 1893 | { | ||
2860 | 1894 | case 'array': | ||
2861 | 1895 | if($val->arraysize() != 1) | ||
2862 | 1896 | { | ||
2863 | 1897 | return false; // Bad value | ||
2864 | 1898 | } | ||
2865 | 1899 | // Normal return value | ||
2866 | 1900 | $response[$i] = new xmlrpcresp($val->arraymem(0)); | ||
2867 | 1901 | break; | ||
2868 | 1902 | case 'struct': | ||
2869 | 1903 | $code = $val->structmem('faultCode'); | ||
2870 | 1904 | if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int') | ||
2871 | 1905 | { | ||
2872 | 1906 | return false; | ||
2873 | 1907 | } | ||
2874 | 1908 | $str = $val->structmem('faultString'); | ||
2875 | 1909 | if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string') | ||
2876 | 1910 | { | ||
2877 | 1911 | return false; | ||
2878 | 1912 | } | ||
2879 | 1913 | $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); | ||
2880 | 1914 | break; | ||
2881 | 1915 | default: | ||
2882 | 1916 | return false; | ||
2883 | 1917 | } | ||
2884 | 1918 | } | ||
2885 | 1919 | return $response; | ||
2886 | 1920 | } | ||
2887 | 1921 | } | ||
2888 | 1922 | } // end class xmlrpc_client | ||
2889 | 1923 | |||
2890 | 1924 | class xmlrpcresp | ||
2891 | 1925 | { | ||
2892 | 1926 | var $val = 0; | ||
2893 | 1927 | var $valtyp; | ||
2894 | 1928 | var $errno = 0; | ||
2895 | 1929 | var $errstr = ''; | ||
2896 | 1930 | var $payload; | ||
2897 | 1931 | var $hdrs = array(); | ||
2898 | 1932 | var $_cookies = array(); | ||
2899 | 1933 | var $content_type = 'text/xml'; | ||
2900 | 1934 | var $raw_data = ''; | ||
2901 | 1935 | |||
2902 | 1936 | /** | ||
2903 | 1937 | * @param mixed $val either an xmlrpcval obj, a php value or the xml serialization of an xmlrpcval (a string) | ||
2904 | 1938 | * @param integer $fcode set it to anything but 0 to create an error response | ||
2905 | 1939 | * @param string $fstr the error string, in case of an error response | ||
2906 | 1940 | * @param string $valtyp either 'xmlrpcvals', 'phpvals' or 'xml' | ||
2907 | 1941 | * | ||
2908 | 1942 | * @todo add check that $val / $fcode / $fstr is of correct type??? | ||
2909 | 1943 | * NB: as of now we do not do it, since it might be either an xmlrpcval or a plain | ||
2910 | 1944 | * php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called... | ||
2911 | 1945 | */ | ||
2912 | 1946 | function xmlrpcresp($val, $fcode = 0, $fstr = '', $valtyp='') | ||
2913 | 1947 | { | ||
2914 | 1948 | if($fcode != 0) | ||
2915 | 1949 | { | ||
2916 | 1950 | // error response | ||
2917 | 1951 | $this->errno = $fcode; | ||
2918 | 1952 | $this->errstr = $fstr; | ||
2919 | 1953 | //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later. | ||
2920 | 1954 | } | ||
2921 | 1955 | else | ||
2922 | 1956 | { | ||
2923 | 1957 | // successful response | ||
2924 | 1958 | $this->val = $val; | ||
2925 | 1959 | if ($valtyp == '') | ||
2926 | 1960 | { | ||
2927 | 1961 | // user did not declare type of response value: try to guess it | ||
2928 | 1962 | if (is_object($this->val) && is_a($this->val, 'xmlrpcval')) | ||
2929 | 1963 | { | ||
2930 | 1964 | $this->valtyp = 'xmlrpcvals'; | ||
2931 | 1965 | } | ||
2932 | 1966 | else if (is_string($this->val)) | ||
2933 | 1967 | { | ||
2934 | 1968 | $this->valtyp = 'xml'; | ||
2935 | 1969 | |||
2936 | 1970 | } | ||
2937 | 1971 | else | ||
2938 | 1972 | { | ||
2939 | 1973 | $this->valtyp = 'phpvals'; | ||
2940 | 1974 | } | ||
2941 | 1975 | } | ||
2942 | 1976 | else | ||
2943 | 1977 | { | ||
2944 | 1978 | // user declares type of resp value: believe him | ||
2945 | 1979 | $this->valtyp = $valtyp; | ||
2946 | 1980 | } | ||
2947 | 1981 | } | ||
2948 | 1982 | } | ||
2949 | 1983 | |||
2950 | 1984 | /** | ||
2951 | 1985 | * Returns the error code of the response. | ||
2952 | 1986 | * @return integer the error code of this response (0 for not-error responses) | ||
2953 | 1987 | * @access public | ||
2954 | 1988 | */ | ||
2955 | 1989 | function faultCode() | ||
2956 | 1990 | { | ||
2957 | 1991 | return $this->errno; | ||
2958 | 1992 | } | ||
2959 | 1993 | |||
2960 | 1994 | /** | ||
2961 | 1995 | * Returns the error code of the response. | ||
2962 | 1996 | * @return string the error string of this response ('' for not-error responses) | ||
2963 | 1997 | * @access public | ||
2964 | 1998 | */ | ||
2965 | 1999 | function faultString() | ||
2966 | 2000 | { | ||
2967 | 2001 | return $this->errstr; | ||
2968 | 2002 | } | ||
2969 | 2003 | |||
2970 | 2004 | /** | ||
2971 | 2005 | * Returns the value received by the server. | ||
2972 | 2006 | * @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects | ||
2973 | 2007 | * @access public | ||
2974 | 2008 | */ | ||
2975 | 2009 | function value() | ||
2976 | 2010 | { | ||
2977 | 2011 | return $this->val; | ||
2978 | 2012 | } | ||
2979 | 2013 | |||
2980 | 2014 | /** | ||
2981 | 2015 | * Returns an array with the cookies received from the server. | ||
2982 | 2016 | * Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 = $val2, ...) | ||
2983 | 2017 | * with attributes being e.g. 'expires', 'path', domain'. | ||
2984 | 2018 | * NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past) | ||
2985 | 2019 | * are still present in the array. It is up to the user-defined code to decide | ||
2986 | 2020 | * how to use the received cookies, and wheter they have to be sent back with the next | ||
2987 | 2021 | * request to the server (using xmlrpc_client::setCookie) or not | ||
2988 | 2022 | * @return array array of cookies received from the server | ||
2989 | 2023 | * @access public | ||
2990 | 2024 | */ | ||
2991 | 2025 | function cookies() | ||
2992 | 2026 | { | ||
2993 | 2027 | return $this->_cookies; | ||
2994 | 2028 | } | ||
2995 | 2029 | |||
2996 | 2030 | /** | ||
2997 | 2031 | * Returns xml representation of the response. XML prologue not included | ||
2998 | 2032 | * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed | ||
2999 | 2033 | * @return string the xml representation of the response | ||
3000 | 2034 | * @access public | ||
3001 | 2035 | */ | ||
3002 | 2036 | function serialize($charset_encoding='') | ||
3003 | 2037 | { | ||
3004 | 2038 | if ($charset_encoding != '') | ||
3005 | 2039 | $this->content_type = 'text/xml; charset=' . $charset_encoding; | ||
3006 | 2040 | else | ||
3007 | 2041 | $this->content_type = 'text/xml'; | ||
3008 | 2042 | $result = "<methodResponse>\n"; | ||
3009 | 2043 | if($this->errno) | ||
3010 | 2044 | { | ||
3011 | 2045 | // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients | ||
3012 | 2046 | // by xml-encoding non ascii chars | ||
3013 | 2047 | $result .= "<fault>\n" . | ||
3014 | 2048 | "<value>\n<struct><member><name>faultCode</name>\n<value><int>" . $this->errno . | ||
3015 | 2049 | "</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>" . | ||
3016 | 2050 | xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "</string></value>\n</member>\n" . | ||
3017 | 2051 | "</struct>\n</value>\n</fault>"; | ||
3018 | 2052 | } | ||
3019 | 2053 | else | ||
3020 | 2054 | { | ||
3021 | 2055 | if(!is_object($this->val) || !is_a($this->val, 'xmlrpcval')) | ||
3022 | 2056 | { | ||
3023 | 2057 | if (is_string($this->val) && $this->valtyp == 'xml') | ||
3024 | 2058 | { | ||
3025 | 2059 | $result .= "<params>\n<param>\n" . | ||
3026 | 2060 | $this->val . | ||
3027 | 2061 | "</param>\n</params>"; | ||
3028 | 2062 | } | ||
3029 | 2063 | else | ||
3030 | 2064 | { | ||
3031 | 2065 | /// @todo try to build something serializable? | ||
3032 | 2066 | die('cannot serialize xmlrpcresp objects whose content is native php values'); | ||
3033 | 2067 | } | ||
3034 | 2068 | } | ||
3035 | 2069 | else | ||
3036 | 2070 | { | ||
3037 | 2071 | $result .= "<params>\n<param>\n" . | ||
3038 | 2072 | $this->val->serialize($charset_encoding) . | ||
3039 | 2073 | "</param>\n</params>"; | ||
3040 | 2074 | } | ||
3041 | 2075 | } | ||
3042 | 2076 | $result .= "\n</methodResponse>"; | ||
3043 | 2077 | $this->payload = $result; | ||
3044 | 2078 | return $result; | ||
3045 | 2079 | } | ||
3046 | 2080 | } | ||
3047 | 2081 | |||
3048 | 2082 | class xmlrpcmsg | ||
3049 | 2083 | { | ||
3050 | 2084 | var $payload; | ||
3051 | 2085 | var $methodname; | ||
3052 | 2086 | var $params=array(); | ||
3053 | 2087 | var $debug=0; | ||
3054 | 2088 | var $content_type = 'text/xml'; | ||
3055 | 2089 | |||
3056 | 2090 | /** | ||
3057 | 2091 | * @param string $meth the name of the method to invoke | ||
3058 | 2092 | * @param array $pars array of parameters to be paased to the method (xmlrpcval objects) | ||
3059 | 2093 | */ | ||
3060 | 2094 | function xmlrpcmsg($meth, $pars=0) | ||
3061 | 2095 | { | ||
3062 | 2096 | $this->methodname=$meth; | ||
3063 | 2097 | if(is_array($pars) && count($pars)>0) | ||
3064 | 2098 | { | ||
3065 | 2099 | for($i=0; $i<count($pars); $i++) | ||
3066 | 2100 | { | ||
3067 | 2101 | $this->addParam($pars[$i]); | ||
3068 | 2102 | } | ||
3069 | 2103 | } | ||
3070 | 2104 | } | ||
3071 | 2105 | |||
3072 | 2106 | /** | ||
3073 | 2107 | * @access private | ||
3074 | 2108 | */ | ||
3075 | 2109 | function xml_header($charset_encoding='') | ||
3076 | 2110 | { | ||
3077 | 2111 | if ($charset_encoding != '') | ||
3078 | 2112 | { | ||
3079 | 2113 | return "<?xml version=\"1.0\" encoding=\"$charset_encoding\" ?" . ">\n<methodCall>\n"; | ||
3080 | 2114 | } | ||
3081 | 2115 | else | ||
3082 | 2116 | { | ||
3083 | 2117 | return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n"; | ||
3084 | 2118 | } | ||
3085 | 2119 | } | ||
3086 | 2120 | |||
3087 | 2121 | /** | ||
3088 | 2122 | * @access private | ||
3089 | 2123 | */ | ||
3090 | 2124 | function xml_footer() | ||
3091 | 2125 | { | ||
3092 | 2126 | return '</methodCall>'; | ||
3093 | 2127 | } | ||
3094 | 2128 | |||
3095 | 2129 | /** | ||
3096 | 2130 | * @access private | ||
3097 | 2131 | */ | ||
3098 | 2132 | function kindOf() | ||
3099 | 2133 | { | ||
3100 | 2134 | return 'msg'; | ||
3101 | 2135 | } | ||
3102 | 2136 | |||
3103 | 2137 | /** | ||
3104 | 2138 | * @access private | ||
3105 | 2139 | */ | ||
3106 | 2140 | function createPayload($charset_encoding='') | ||
3107 | 2141 | { | ||
3108 | 2142 | if ($charset_encoding != '') | ||
3109 | 2143 | $this->content_type = 'text/xml; charset=' . $charset_encoding; | ||
3110 | 2144 | else | ||
3111 | 2145 | $this->content_type = 'text/xml'; | ||
3112 | 2146 | $this->payload=$this->xml_header($charset_encoding); | ||
3113 | 2147 | $this->payload.='<methodName>' . $this->methodname . "</methodName>\n"; | ||
3114 | 2148 | $this->payload.="<params>\n"; | ||
3115 | 2149 | for($i=0; $i<count($this->params); $i++) | ||
3116 | 2150 | { | ||
3117 | 2151 | $p=$this->params[$i]; | ||
3118 | 2152 | $this->payload.="<param>\n" . $p->serialize($charset_encoding) . | ||
3119 | 2153 | "</param>\n"; | ||
3120 | 2154 | } | ||
3121 | 2155 | $this->payload.="</params>\n"; | ||
3122 | 2156 | $this->payload.=$this->xml_footer(); | ||
3123 | 2157 | } | ||
3124 | 2158 | |||
3125 | 2159 | /** | ||
3126 | 2160 | * Gets/sets the xmlrpc method to be invoked | ||
3127 | 2161 | * @param string $meth the method to be set (leave empty not to set it) | ||
3128 | 2162 | * @return string the method that will be invoked | ||
3129 | 2163 | * @access public | ||
3130 | 2164 | */ | ||
3131 | 2165 | function method($meth='') | ||
3132 | 2166 | { | ||
3133 | 2167 | if($meth!='') | ||
3134 | 2168 | { | ||
3135 | 2169 | $this->methodname=$meth; | ||
3136 | 2170 | } | ||
3137 | 2171 | return $this->methodname; | ||
3138 | 2172 | } | ||
3139 | 2173 | |||
3140 | 2174 | /** | ||
3141 | 2175 | * Returns xml representation of the message. XML prologue included | ||
3142 | 2176 | * @return string the xml representation of the message, xml prologue included | ||
3143 | 2177 | * @access public | ||
3144 | 2178 | */ | ||
3145 | 2179 | function serialize($charset_encoding='') | ||
3146 | 2180 | { | ||
3147 | 2181 | $this->createPayload($charset_encoding); | ||
3148 | 2182 | return $this->payload; | ||
3149 | 2183 | } | ||
3150 | 2184 | |||
3151 | 2185 | /** | ||
3152 | 2186 | * Add a parameter to the list of parameters to be used upon method invocation | ||
3153 | 2187 | * @param xmlrpcval $par | ||
3154 | 2188 | * @return boolean false on failure | ||
3155 | 2189 | * @access public | ||
3156 | 2190 | */ | ||
3157 | 2191 | function addParam($par) | ||
3158 | 2192 | { | ||
3159 | 2193 | // add check: do not add to self params which are not xmlrpcvals | ||
3160 | 2194 | if(is_object($par) && is_a($par, 'xmlrpcval')) | ||
3161 | 2195 | { | ||
3162 | 2196 | $this->params[]=$par; | ||
3163 | 2197 | return true; | ||
3164 | 2198 | } | ||
3165 | 2199 | else | ||
3166 | 2200 | { | ||
3167 | 2201 | return false; | ||
3168 | 2202 | } | ||
3169 | 2203 | } | ||
3170 | 2204 | |||
3171 | 2205 | /** | ||
3172 | 2206 | * Returns the nth parameter in the message. The index zero-based. | ||
3173 | 2207 | * @param integer $i the index of the parameter to fetch (zero based) | ||
3174 | 2208 | * @return xmlrpcval the i-th parameter | ||
3175 | 2209 | * @access public | ||
3176 | 2210 | */ | ||
3177 | 2211 | function getParam($i) { return $this->params[$i]; } | ||
3178 | 2212 | |||
3179 | 2213 | /** | ||
3180 | 2214 | * Returns the number of parameters in the messge. | ||
3181 | 2215 | * @return integer the number of parameters currently set | ||
3182 | 2216 | * @access public | ||
3183 | 2217 | */ | ||
3184 | 2218 | function getNumParams() { return count($this->params); } | ||
3185 | 2219 | |||
3186 | 2220 | /** | ||
3187 | 2221 | * Given an open file handle, read all data available and parse it as axmlrpc response. | ||
3188 | 2222 | * NB: the file handle is not closed by this function. | ||
3189 | 2223 | * NNB: might have trouble in rare cases to work on network streams, as we | ||
3190 | 2224 | * check for a read of 0 bytes instead of feof($fp). | ||
3191 | 2225 | * But since checking for feof(null) returns false, we would risk an | ||
3192 | 2226 | * infinite loop in that case, because we cannot trust the caller | ||
3193 | 2227 | * to give us a valid pointer to an open file... | ||
3194 | 2228 | * @access public | ||
3195 | 2229 | * @return xmlrpcresp | ||
3196 | 2230 | * @todo add 2nd & 3rd param to be passed to ParseResponse() ??? | ||
3197 | 2231 | */ | ||
3198 | 2232 | function &parseResponseFile($fp) | ||
3199 | 2233 | { | ||
3200 | 2234 | $ipd=''; | ||
3201 | 2235 | while($data=fread($fp, 32768)) | ||
3202 | 2236 | { | ||
3203 | 2237 | $ipd.=$data; | ||
3204 | 2238 | } | ||
3205 | 2239 | //fclose($fp); | ||
3206 | 2240 | $r =& $this->parseResponse($ipd); | ||
3207 | 2241 | return $r; | ||
3208 | 2242 | } | ||
3209 | 2243 | |||
3210 | 2244 | /** | ||
3211 | 2245 | * Parses HTTP headers and separates them from data. | ||
3212 | 2246 | * @access private | ||
3213 | 2247 | */ | ||
3214 | 2248 | function &parseResponseHeaders(&$data, $headers_processed=false) | ||
3215 | 2249 | { | ||
3216 | 2250 | // Support "web-proxy-tunelling" connections for https through proxies | ||
3217 | 2251 | if(preg_match('/^HTTP\/1\.[0-1] 200 Connection established/', $data)) | ||
3218 | 2252 | { | ||
3219 | 2253 | // Look for CR/LF or simple LF as line separator, | ||
3220 | 2254 | // (even though it is not valid http) | ||
3221 | 2255 | $pos = strpos($data,"\r\n\r\n"); | ||
3222 | 2256 | if($pos || is_int($pos)) | ||
3223 | 2257 | { | ||
3224 | 2258 | $bd = $pos+4; | ||
3225 | 2259 | } | ||
3226 | 2260 | else | ||
3227 | 2261 | { | ||
3228 | 2262 | $pos = strpos($data,"\n\n"); | ||
3229 | 2263 | if($pos || is_int($pos)) | ||
3230 | 2264 | { | ||
3231 | 2265 | $bd = $pos+2; | ||
3232 | 2266 | } | ||
3233 | 2267 | else | ||
3234 | 2268 | { | ||
3235 | 2269 | // No separation between response headers and body: fault? | ||
3236 | 2270 | $bd = 0; | ||
3237 | 2271 | } | ||
3238 | 2272 | } | ||
3239 | 2273 | if ($bd) | ||
3240 | 2274 | { | ||
3241 | 2275 | // this filters out all http headers from proxy. | ||
3242 | 2276 | // maybe we could take them into account, too? | ||
3243 | 2277 | $data = substr($data, $bd); | ||
3244 | 2278 | } | ||
3245 | 2279 | else | ||
3246 | 2280 | { | ||
3247 | 2281 | error_log('XML-RPC: '.__METHOD__.': HTTPS via proxy error, tunnel connection possibly failed'); | ||
3248 | 2282 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)'); | ||
3249 | 2283 | return $r; | ||
3250 | 2284 | } | ||
3251 | 2285 | } | ||
3252 | 2286 | |||
3253 | 2287 | // Strip HTTP 1.1 100 Continue header if present | ||
3254 | 2288 | while(preg_match('/^HTTP\/1\.1 1[0-9]{2} /', $data)) | ||
3255 | 2289 | { | ||
3256 | 2290 | $pos = strpos($data, 'HTTP', 12); | ||
3257 | 2291 | // server sent a Continue header without any (valid) content following... | ||
3258 | 2292 | // give the client a chance to know it | ||
3259 | 2293 | if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5 | ||
3260 | 2294 | { | ||
3261 | 2295 | break; | ||
3262 | 2296 | } | ||
3263 | 2297 | $data = substr($data, $pos); | ||
3264 | 2298 | } | ||
3265 | 2299 | if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data)) | ||
3266 | 2300 | { | ||
3267 | 2301 | $errstr= substr($data, 0, strpos($data, "\n")-1); | ||
3268 | 2302 | error_log('XML-RPC: '.__METHOD__.': HTTP error, got response: ' .$errstr); | ||
3269 | 2303 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')'); | ||
3270 | 2304 | return $r; | ||
3271 | 2305 | } | ||
3272 | 2306 | |||
3273 | 2307 | $GLOBALS['_xh']['headers'] = array(); | ||
3274 | 2308 | $GLOBALS['_xh']['cookies'] = array(); | ||
3275 | 2309 | |||
3276 | 2310 | // be tolerant to usage of \n instead of \r\n to separate headers and data | ||
3277 | 2311 | // (even though it is not valid http) | ||
3278 | 2312 | $pos = strpos($data,"\r\n\r\n"); | ||
3279 | 2313 | if($pos || is_int($pos)) | ||
3280 | 2314 | { | ||
3281 | 2315 | $bd = $pos+4; | ||
3282 | 2316 | } | ||
3283 | 2317 | else | ||
3284 | 2318 | { | ||
3285 | 2319 | $pos = strpos($data,"\n\n"); | ||
3286 | 2320 | if($pos || is_int($pos)) | ||
3287 | 2321 | { | ||
3288 | 2322 | $bd = $pos+2; | ||
3289 | 2323 | } | ||
3290 | 2324 | else | ||
3291 | 2325 | { | ||
3292 | 2326 | // No separation between response headers and body: fault? | ||
3293 | 2327 | // we could take some action here instead of going on... | ||
3294 | 2328 | $bd = 0; | ||
3295 | 2329 | } | ||
3296 | 2330 | } | ||
3297 | 2331 | // be tolerant to line endings, and extra empty lines | ||
3298 | 2332 | $ar = preg_split("/\r?\n/", trim(substr($data, 0, $pos))); | ||
3299 | 2333 | while(list(,$line) = @each($ar)) | ||
3300 | 2334 | { | ||
3301 | 2335 | // take care of multi-line headers and cookies | ||
3302 | 2336 | $arr = explode(':',$line,2); | ||
3303 | 2337 | if(count($arr) > 1) | ||
3304 | 2338 | { | ||
3305 | 2339 | $header_name = strtolower(trim($arr[0])); | ||
3306 | 2340 | /// @todo some other headers (the ones that allow a CSV list of values) | ||
3307 | 2341 | /// do allow many values to be passed using multiple header lines. | ||
3308 | 2342 | /// We should add content to $GLOBALS['_xh']['headers'][$header_name] | ||
3309 | 2343 | /// instead of replacing it for those... | ||
3310 | 2344 | if ($header_name == 'set-cookie' || $header_name == 'set-cookie2') | ||
3311 | 2345 | { | ||
3312 | 2346 | if ($header_name == 'set-cookie2') | ||
3313 | 2347 | { | ||
3314 | 2348 | // version 2 cookies: | ||
3315 | 2349 | // there could be many cookies on one line, comma separated | ||
3316 | 2350 | $cookies = explode(',', $arr[1]); | ||
3317 | 2351 | } | ||
3318 | 2352 | else | ||
3319 | 2353 | { | ||
3320 | 2354 | $cookies = array($arr[1]); | ||
3321 | 2355 | } | ||
3322 | 2356 | foreach ($cookies as $cookie) | ||
3323 | 2357 | { | ||
3324 | 2358 | // glue together all received cookies, using a comma to separate them | ||
3325 | 2359 | // (same as php does with getallheaders()) | ||
3326 | 2360 | if (isset($GLOBALS['_xh']['headers'][$header_name])) | ||
3327 | 2361 | $GLOBALS['_xh']['headers'][$header_name] .= ', ' . trim($cookie); | ||
3328 | 2362 | else | ||
3329 | 2363 | $GLOBALS['_xh']['headers'][$header_name] = trim($cookie); | ||
3330 | 2364 | // parse cookie attributes, in case user wants to correctly honour them | ||
3331 | 2365 | // feature creep: only allow rfc-compliant cookie attributes? | ||
3332 | 2366 | // @todo support for server sending multiple time cookie with same name, but using different PATHs | ||
3333 | 2367 | $cookie = explode(';', $cookie); | ||
3334 | 2368 | foreach ($cookie as $pos => $val) | ||
3335 | 2369 | { | ||
3336 | 2370 | $val = explode('=', $val, 2); | ||
3337 | 2371 | $tag = trim($val[0]); | ||
3338 | 2372 | $val = trim(@$val[1]); | ||
3339 | 2373 | /// @todo with version 1 cookies, we should strip leading and trailing " chars | ||
3340 | 2374 | if ($pos == 0) | ||
3341 | 2375 | { | ||
3342 | 2376 | $cookiename = $tag; | ||
3343 | 2377 | $GLOBALS['_xh']['cookies'][$tag] = array(); | ||
3344 | 2378 | $GLOBALS['_xh']['cookies'][$cookiename]['value'] = urldecode($val); | ||
3345 | 2379 | } | ||
3346 | 2380 | else | ||
3347 | 2381 | { | ||
3348 | 2382 | if ($tag != 'value') | ||
3349 | 2383 | { | ||
3350 | 2384 | $GLOBALS['_xh']['cookies'][$cookiename][$tag] = $val; | ||
3351 | 2385 | } | ||
3352 | 2386 | } | ||
3353 | 2387 | } | ||
3354 | 2388 | } | ||
3355 | 2389 | } | ||
3356 | 2390 | else | ||
3357 | 2391 | { | ||
3358 | 2392 | $GLOBALS['_xh']['headers'][$header_name] = trim($arr[1]); | ||
3359 | 2393 | } | ||
3360 | 2394 | } | ||
3361 | 2395 | elseif(isset($header_name)) | ||
3362 | 2396 | { | ||
3363 | 2397 | /// @todo version1 cookies might span multiple lines, thus breaking the parsing above | ||
3364 | 2398 | $GLOBALS['_xh']['headers'][$header_name] .= ' ' . trim($line); | ||
3365 | 2399 | } | ||
3366 | 2400 | } | ||
3367 | 2401 | |||
3368 | 2402 | $data = substr($data, $bd); | ||
3369 | 2403 | |||
3370 | 2404 | if($this->debug && count($GLOBALS['_xh']['headers'])) | ||
3371 | 2405 | { | ||
3372 | 2406 | print '<PRE>'; | ||
3373 | 2407 | foreach($GLOBALS['_xh']['headers'] as $header => $value) | ||
3374 | 2408 | { | ||
3375 | 2409 | print htmlentities("HEADER: $header: $value\n"); | ||
3376 | 2410 | } | ||
3377 | 2411 | foreach($GLOBALS['_xh']['cookies'] as $header => $value) | ||
3378 | 2412 | { | ||
3379 | 2413 | print htmlentities("COOKIE: $header={$value['value']}\n"); | ||
3380 | 2414 | } | ||
3381 | 2415 | print "</PRE>\n"; | ||
3382 | 2416 | } | ||
3383 | 2417 | |||
3384 | 2418 | // if CURL was used for the call, http headers have been processed, | ||
3385 | 2419 | // and dechunking + reinflating have been carried out | ||
3386 | 2420 | if(!$headers_processed) | ||
3387 | 2421 | { | ||
3388 | 2422 | // Decode chunked encoding sent by http 1.1 servers | ||
3389 | 2423 | if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked') | ||
3390 | 2424 | { | ||
3391 | 2425 | if(!$data = decode_chunked($data)) | ||
3392 | 2426 | { | ||
3393 | 2427 | error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to rebuild the chunked data received from server'); | ||
3394 | 2428 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']); | ||
3395 | 2429 | return $r; | ||
3396 | 2430 | } | ||
3397 | 2431 | } | ||
3398 | 2432 | |||
3399 | 2433 | // Decode gzip-compressed stuff | ||
3400 | 2434 | // code shamelessly inspired from nusoap library by Dietrich Ayala | ||
3401 | 2435 | if(isset($GLOBALS['_xh']['headers']['content-encoding'])) | ||
3402 | 2436 | { | ||
3403 | 2437 | $GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']); | ||
3404 | 2438 | if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip') | ||
3405 | 2439 | { | ||
3406 | 2440 | // if decoding works, use it. else assume data wasn't gzencoded | ||
3407 | 2441 | if(function_exists('gzinflate')) | ||
3408 | 2442 | { | ||
3409 | 2443 | if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) | ||
3410 | 2444 | { | ||
3411 | 2445 | $data = $degzdata; | ||
3412 | 2446 | if($this->debug) | ||
3413 | 2447 | print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>"; | ||
3414 | 2448 | } | ||
3415 | 2449 | elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10))) | ||
3416 | 2450 | { | ||
3417 | 2451 | $data = $degzdata; | ||
3418 | 2452 | if($this->debug) | ||
3419 | 2453 | print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>"; | ||
3420 | 2454 | } | ||
3421 | 2455 | else | ||
3422 | 2456 | { | ||
3423 | 2457 | error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to decode the deflated data received from server'); | ||
3424 | 2458 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']); | ||
3425 | 2459 | return $r; | ||
3426 | 2460 | } | ||
3427 | 2461 | } | ||
3428 | 2462 | else | ||
3429 | 2463 | { | ||
3430 | 2464 | error_log('XML-RPC: '.__METHOD__.': the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); | ||
3431 | 2465 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']); | ||
3432 | 2466 | return $r; | ||
3433 | 2467 | } | ||
3434 | 2468 | } | ||
3435 | 2469 | } | ||
3436 | 2470 | } // end of 'if needed, de-chunk, re-inflate response' | ||
3437 | 2471 | |||
3438 | 2472 | // real stupid hack to avoid PHP complaining about returning NULL by ref | ||
3439 | 2473 | $r = null; | ||
3440 | 2474 | $r =& $r; | ||
3441 | 2475 | return $r; | ||
3442 | 2476 | } | ||
3443 | 2477 | |||
3444 | 2478 | /** | ||
3445 | 2479 | * Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object. | ||
3446 | 2480 | * @param string $data the xmlrpc response, eventually including http headers | ||
3447 | 2481 | * @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding | ||
3448 | 2482 | * @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals' | ||
3449 | 2483 | * @return xmlrpcresp | ||
3450 | 2484 | * @access public | ||
3451 | 2485 | */ | ||
3452 | 2486 | function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals') | ||
3453 | 2487 | { | ||
3454 | 2488 | if($this->debug) | ||
3455 | 2489 | { | ||
3456 | 2490 | //by maHo, replaced htmlspecialchars with htmlentities | ||
3457 | 2491 | print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>"; | ||
3458 | 2492 | } | ||
3459 | 2493 | |||
3460 | 2494 | if($data == '') | ||
3461 | 2495 | { | ||
3462 | 2496 | error_log('XML-RPC: '.__METHOD__.': no response received from server.'); | ||
3463 | 2497 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']); | ||
3464 | 2498 | return $r; | ||
3465 | 2499 | } | ||
3466 | 2500 | |||
3467 | 2501 | $GLOBALS['_xh']=array(); | ||
3468 | 2502 | |||
3469 | 2503 | $raw_data = $data; | ||
3470 | 2504 | // parse the HTTP headers of the response, if present, and separate them from data | ||
3471 | 2505 | if(substr($data, 0, 4) == 'HTTP') | ||
3472 | 2506 | { | ||
3473 | 2507 | $r =& $this->parseResponseHeaders($data, $headers_processed); | ||
3474 | 2508 | if ($r) | ||
3475 | 2509 | { | ||
3476 | 2510 | // failed processing of HTTP response headers | ||
3477 | 2511 | // save into response obj the full payload received, for debugging | ||
3478 | 2512 | $r->raw_data = $data; | ||
3479 | 2513 | return $r; | ||
3480 | 2514 | } | ||
3481 | 2515 | } | ||
3482 | 2516 | else | ||
3483 | 2517 | { | ||
3484 | 2518 | $GLOBALS['_xh']['headers'] = array(); | ||
3485 | 2519 | $GLOBALS['_xh']['cookies'] = array(); | ||
3486 | 2520 | } | ||
3487 | 2521 | |||
3488 | 2522 | if($this->debug) | ||
3489 | 2523 | { | ||
3490 | 2524 | $start = strpos($data, '<!-- SERVER DEBUG INFO (BASE64 ENCODED):'); | ||
3491 | 2525 | if ($start) | ||
3492 | 2526 | { | ||
3493 | 2527 | $start += strlen('<!-- SERVER DEBUG INFO (BASE64 ENCODED):'); | ||
3494 | 2528 | $end = strpos($data, '-->', $start); | ||
3495 | 2529 | $comments = substr($data, $start, $end-$start); | ||
3496 | 2530 | print "<PRE>---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n</PRE>"; | ||
3497 | 2531 | } | ||
3498 | 2532 | } | ||
3499 | 2533 | |||
3500 | 2534 | // be tolerant of extra whitespace in response body | ||
3501 | 2535 | $data = trim($data); | ||
3502 | 2536 | |||
3503 | 2537 | /// @todo return an error msg if $data=='' ? | ||
3504 | 2538 | |||
3505 | 2539 | // be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts) | ||
3506 | 2540 | // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib | ||
3507 | 2541 | $pos = strrpos($data, '</methodResponse>'); | ||
3508 | 2542 | if($pos !== false) | ||
3509 | 2543 | { | ||
3510 | 2544 | $data = substr($data, 0, $pos+17); | ||
3511 | 2545 | } | ||
3512 | 2546 | |||
3513 | 2547 | // if user wants back raw xml, give it to him | ||
3514 | 2548 | if ($return_type == 'xml') | ||
3515 | 2549 | { | ||
3516 | 2550 | $r = new xmlrpcresp($data, 0, '', 'xml'); | ||
3517 | 2551 | $r->hdrs = $GLOBALS['_xh']['headers']; | ||
3518 | 2552 | $r->_cookies = $GLOBALS['_xh']['cookies']; | ||
3519 | 2553 | $r->raw_data = $raw_data; | ||
3520 | 2554 | return $r; | ||
3521 | 2555 | } | ||
3522 | 2556 | |||
3523 | 2557 | // try to 'guestimate' the character encoding of the received response | ||
3524 | 2558 | $resp_encoding = guess_encoding(@$GLOBALS['_xh']['headers']['content-type'], $data); | ||
3525 | 2559 | |||
3526 | 2560 | $GLOBALS['_xh']['ac']=''; | ||
3527 | 2561 | //$GLOBALS['_xh']['qt']=''; //unused... | ||
3528 | 2562 | $GLOBALS['_xh']['stack'] = array(); | ||
3529 | 2563 | $GLOBALS['_xh']['valuestack'] = array(); | ||
3530 | 2564 | $GLOBALS['_xh']['isf']=0; // 0 = OK, 1 for xmlrpc fault responses, 2 = invalid xmlrpc | ||
3531 | 2565 | $GLOBALS['_xh']['isf_reason']=''; | ||
3532 | 2566 | $GLOBALS['_xh']['rt']=''; // 'methodcall or 'methodresponse' | ||
3533 | 2567 | |||
3534 | 2568 | // if response charset encoding is not known / supported, try to use | ||
3535 | 2569 | // the default encoding and parse the xml anyway, but log a warning... | ||
3536 | 2570 | if (!in_array($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) | ||
3537 | 2571 | // the following code might be better for mb_string enabled installs, but | ||
3538 | 2572 | // makes the lib about 200% slower... | ||
3539 | 2573 | //if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) | ||
3540 | 2574 | { | ||
3541 | 2575 | error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received response: '.$resp_encoding); | ||
3542 | 2576 | $resp_encoding = $GLOBALS['xmlrpc_defencoding']; | ||
3543 | 2577 | } | ||
3544 | 2578 | $parser = xml_parser_create($resp_encoding); | ||
3545 | 2579 | xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); | ||
3546 | 2580 | // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell | ||
3547 | 2581 | // the xml parser to give us back data in the expected charset. | ||
3548 | 2582 | // What if internal encoding is not in one of the 3 allowed? | ||
3549 | 2583 | // we use the broadest one, ie. utf8 | ||
3550 | 2584 | // This allows to send data which is native in various charset, | ||
3551 | 2585 | // by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding | ||
3552 | 2586 | if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) | ||
3553 | 2587 | { | ||
3554 | 2588 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); | ||
3555 | 2589 | } | ||
3556 | 2590 | else | ||
3557 | 2591 | { | ||
3558 | 2592 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); | ||
3559 | 2593 | } | ||
3560 | 2594 | |||
3561 | 2595 | if ($return_type == 'phpvals') | ||
3562 | 2596 | { | ||
3563 | 2597 | xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast'); | ||
3564 | 2598 | } | ||
3565 | 2599 | else | ||
3566 | 2600 | { | ||
3567 | 2601 | xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); | ||
3568 | 2602 | } | ||
3569 | 2603 | |||
3570 | 2604 | xml_set_character_data_handler($parser, 'xmlrpc_cd'); | ||
3571 | 2605 | xml_set_default_handler($parser, 'xmlrpc_dh'); | ||
3572 | 2606 | |||
3573 | 2607 | // first error check: xml not well formed | ||
3574 | 2608 | if(!xml_parse($parser, $data, count($data))) | ||
3575 | 2609 | { | ||
3576 | 2610 | // thanks to Peter Kocks <peter.kocks@baygate.com> | ||
3577 | 2611 | if((xml_get_current_line_number($parser)) == 1) | ||
3578 | 2612 | { | ||
3579 | 2613 | $errstr = 'XML error at line 1, check URL'; | ||
3580 | 2614 | } | ||
3581 | 2615 | else | ||
3582 | 2616 | { | ||
3583 | 2617 | $errstr = sprintf('XML error: %s at line %d, column %d', | ||
3584 | 2618 | xml_error_string(xml_get_error_code($parser)), | ||
3585 | 2619 | xml_get_current_line_number($parser), xml_get_current_column_number($parser)); | ||
3586 | 2620 | } | ||
3587 | 2621 | error_log($errstr); | ||
3588 | 2622 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')'); | ||
3589 | 2623 | xml_parser_free($parser); | ||
3590 | 2624 | if($this->debug) | ||
3591 | 2625 | { | ||
3592 | 2626 | print $errstr; | ||
3593 | 2627 | } | ||
3594 | 2628 | $r->hdrs = $GLOBALS['_xh']['headers']; | ||
3595 | 2629 | $r->_cookies = $GLOBALS['_xh']['cookies']; | ||
3596 | 2630 | $r->raw_data = $raw_data; | ||
3597 | 2631 | return $r; | ||
3598 | 2632 | } | ||
3599 | 2633 | xml_parser_free($parser); | ||
3600 | 2634 | // second error check: xml well formed but not xml-rpc compliant | ||
3601 | 2635 | if ($GLOBALS['_xh']['isf'] > 1) | ||
3602 | 2636 | { | ||
3603 | 2637 | if ($this->debug) | ||
3604 | 2638 | { | ||
3605 | 2639 | /// @todo echo something for user? | ||
3606 | 2640 | } | ||
3607 | 2641 | |||
3608 | 2642 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], | ||
3609 | 2643 | $GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']); | ||
3610 | 2644 | } | ||
3611 | 2645 | // third error check: parsing of the response has somehow gone boink. | ||
3612 | 2646 | // NB: shall we omit this check, since we trust the parsing code? | ||
3613 | 2647 | elseif ($return_type == 'xmlrpcvals' && !is_object($GLOBALS['_xh']['value'])) | ||
3614 | 2648 | { | ||
3615 | 2649 | // something odd has happened | ||
3616 | 2650 | // and it's time to generate a client side error | ||
3617 | 2651 | // indicating something odd went on | ||
3618 | 2652 | $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], | ||
3619 | 2653 | $GLOBALS['xmlrpcstr']['invalid_return']); | ||
3620 | 2654 | } | ||
3621 | 2655 | else | ||
3622 | 2656 | { | ||
3623 | 2657 | if ($this->debug) | ||
3624 | 2658 | { | ||
3625 | 2659 | print "<PRE>---PARSED---\n"; | ||
3626 | 2660 | // somehow htmlentities chokes on var_export, and some full html string... | ||
3627 | 2661 | //print htmlentitites(var_export($GLOBALS['_xh']['value'], true)); | ||
3628 | 2662 | print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true)); | ||
3629 | 2663 | print "\n---END---</PRE>"; | ||
3630 | 2664 | } | ||
3631 | 2665 | |||
3632 | 2666 | // note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object. | ||
3633 | 2667 | $v =& $GLOBALS['_xh']['value']; | ||
3634 | 2668 | |||
3635 | 2669 | if($GLOBALS['_xh']['isf']) | ||
3636 | 2670 | { | ||
3637 | 2671 | /// @todo we should test here if server sent an int and a string, | ||
3638 | 2672 | /// and/or coerce them into such... | ||
3639 | 2673 | if ($return_type == 'xmlrpcvals') | ||
3640 | 2674 | { | ||
3641 | 2675 | $errno_v = $v->structmem('faultCode'); | ||
3642 | 2676 | $errstr_v = $v->structmem('faultString'); | ||
3643 | 2677 | $errno = $errno_v->scalarval(); | ||
3644 | 2678 | $errstr = $errstr_v->scalarval(); | ||
3645 | 2679 | } | ||
3646 | 2680 | else | ||
3647 | 2681 | { | ||
3648 | 2682 | $errno = $v['faultCode']; | ||
3649 | 2683 | $errstr = $v['faultString']; | ||
3650 | 2684 | } | ||
3651 | 2685 | |||
3652 | 2686 | if($errno == 0) | ||
3653 | 2687 | { | ||
3654 | 2688 | // FAULT returned, errno needs to reflect that | ||
3655 | 2689 | $errno = -1; | ||
3656 | 2690 | } | ||
3657 | 2691 | |||
3658 | 2692 | $r = new xmlrpcresp(0, $errno, $errstr); | ||
3659 | 2693 | } | ||
3660 | 2694 | else | ||
3661 | 2695 | { | ||
3662 | 2696 | $r=new xmlrpcresp($v, 0, '', $return_type); | ||
3663 | 2697 | } | ||
3664 | 2698 | } | ||
3665 | 2699 | |||
3666 | 2700 | $r->hdrs = $GLOBALS['_xh']['headers']; | ||
3667 | 2701 | $r->_cookies = $GLOBALS['_xh']['cookies']; | ||
3668 | 2702 | $r->raw_data = $raw_data; | ||
3669 | 2703 | return $r; | ||
3670 | 2704 | } | ||
3671 | 2705 | } | ||
3672 | 2706 | |||
3673 | 2707 | class xmlrpcval | ||
3674 | 2708 | { | ||
3675 | 2709 | var $me=array(); | ||
3676 | 2710 | var $mytype=0; | ||
3677 | 2711 | var $_php_class=null; | ||
3678 | 2712 | |||
3679 | 2713 | /** | ||
3680 | 2714 | * @param mixed $val | ||
3681 | 2715 | * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed | ||
3682 | 2716 | */ | ||
3683 | 2717 | function xmlrpcval($val=-1, $type='') | ||
3684 | 2718 | { | ||
3685 | 2719 | /// @todo: optimization creep - do not call addXX, do it all inline. | ||
3686 | 2720 | /// downside: booleans will not be coerced anymore | ||
3687 | 2721 | if($val!==-1 || $type!='') | ||
3688 | 2722 | { | ||
3689 | 2723 | // optimization creep: inlined all work done by constructor | ||
3690 | 2724 | switch($type) | ||
3691 | 2725 | { | ||
3692 | 2726 | case '': | ||
3693 | 2727 | $this->mytype=1; | ||
3694 | 2728 | $this->me['string']=$val; | ||
3695 | 2729 | break; | ||
3696 | 2730 | case 'i4': | ||
3697 | 2731 | case 'int': | ||
3698 | 2732 | case 'double': | ||
3699 | 2733 | case 'string': | ||
3700 | 2734 | case 'boolean': | ||
3701 | 2735 | case 'dateTime.iso8601': | ||
3702 | 2736 | case 'base64': | ||
3703 | 2737 | case 'null': | ||
3704 | 2738 | $this->mytype=1; | ||
3705 | 2739 | $this->me[$type]=$val; | ||
3706 | 2740 | break; | ||
3707 | 2741 | case 'array': | ||
3708 | 2742 | $this->mytype=2; | ||
3709 | 2743 | $this->me['array']=$val; | ||
3710 | 2744 | break; | ||
3711 | 2745 | case 'struct': | ||
3712 | 2746 | $this->mytype=3; | ||
3713 | 2747 | $this->me['struct']=$val; | ||
3714 | 2748 | break; | ||
3715 | 2749 | default: | ||
3716 | 2750 | error_log("XML-RPC: ".__METHOD__.": not a known type ($type)"); | ||
3717 | 2751 | } | ||
3718 | 2752 | /*if($type=='') | ||
3719 | 2753 | { | ||
3720 | 2754 | $type='string'; | ||
3721 | 2755 | } | ||
3722 | 2756 | if($GLOBALS['xmlrpcTypes'][$type]==1) | ||
3723 | 2757 | { | ||
3724 | 2758 | $this->addScalar($val,$type); | ||
3725 | 2759 | } | ||
3726 | 2760 | elseif($GLOBALS['xmlrpcTypes'][$type]==2) | ||
3727 | 2761 | { | ||
3728 | 2762 | $this->addArray($val); | ||
3729 | 2763 | } | ||
3730 | 2764 | elseif($GLOBALS['xmlrpcTypes'][$type]==3) | ||
3731 | 2765 | { | ||
3732 | 2766 | $this->addStruct($val); | ||
3733 | 2767 | }*/ | ||
3734 | 2768 | } | ||
3735 | 2769 | } | ||
3736 | 2770 | |||
3737 | 2771 | /** | ||
3738 | 2772 | * Add a single php value to an (unitialized) xmlrpcval | ||
3739 | 2773 | * @param mixed $val | ||
3740 | 2774 | * @param string $type | ||
3741 | 2775 | * @return int 1 or 0 on failure | ||
3742 | 2776 | */ | ||
3743 | 2777 | function addScalar($val, $type='string') | ||
3744 | 2778 | { | ||
3745 | 2779 | $typeof=@$GLOBALS['xmlrpcTypes'][$type]; | ||
3746 | 2780 | if($typeof!=1) | ||
3747 | 2781 | { | ||
3748 | 2782 | error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)"); | ||
3749 | 2783 | return 0; | ||
3750 | 2784 | } | ||
3751 | 2785 | |||
3752 | 2786 | // coerce booleans into correct values | ||
3753 | 2787 | // NB: we should either do it for datetimes, integers and doubles, too, | ||
3754 | 2788 | // or just plain remove this check, implemented on booleans only... | ||
3755 | 2789 | if($type==$GLOBALS['xmlrpcBoolean']) | ||
3756 | 2790 | { | ||
3757 | 2791 | if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false'))) | ||
3758 | 2792 | { | ||
3759 | 2793 | $val=true; | ||
3760 | 2794 | } | ||
3761 | 2795 | else | ||
3762 | 2796 | { | ||
3763 | 2797 | $val=false; | ||
3764 | 2798 | } | ||
3765 | 2799 | } | ||
3766 | 2800 | |||
3767 | 2801 | switch($this->mytype) | ||
3768 | 2802 | { | ||
3769 | 2803 | case 1: | ||
3770 | 2804 | error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value'); | ||
3771 | 2805 | return 0; | ||
3772 | 2806 | case 3: | ||
3773 | 2807 | error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval'); | ||
3774 | 2808 | return 0; | ||
3775 | 2809 | case 2: | ||
3776 | 2810 | // we're adding a scalar value to an array here | ||
3777 | 2811 | //$ar=$this->me['array']; | ||
3778 | 2812 | //$ar[]=new xmlrpcval($val, $type); | ||
3779 | 2813 | //$this->me['array']=$ar; | ||
3780 | 2814 | // Faster (?) avoid all the costly array-copy-by-val done here... | ||
3781 | 2815 | $this->me['array'][]=new xmlrpcval($val, $type); | ||
3782 | 2816 | return 1; | ||
3783 | 2817 | default: | ||
3784 | 2818 | // a scalar, so set the value and remember we're scalar | ||
3785 | 2819 | $this->me[$type]=$val; | ||
3786 | 2820 | $this->mytype=$typeof; | ||
3787 | 2821 | return 1; | ||
3788 | 2822 | } | ||
3789 | 2823 | } | ||
3790 | 2824 | |||
3791 | 2825 | /** | ||
3792 | 2826 | * Add an array of xmlrpcval objects to an xmlrpcval | ||
3793 | 2827 | * @param array $vals | ||
3794 | 2828 | * @return int 1 or 0 on failure | ||
3795 | 2829 | * @access public | ||
3796 | 2830 | * | ||
3797 | 2831 | * @todo add some checking for $vals to be an array of xmlrpcvals? | ||
3798 | 2832 | */ | ||
3799 | 2833 | function addArray($vals) | ||
3800 | 2834 | { | ||
3801 | 2835 | if($this->mytype==0) | ||
3802 | 2836 | { | ||
3803 | 2837 | $this->mytype=$GLOBALS['xmlrpcTypes']['array']; | ||
3804 | 2838 | $this->me['array']=$vals; | ||
3805 | 2839 | return 1; | ||
3806 | 2840 | } | ||
3807 | 2841 | elseif($this->mytype==2) | ||
3808 | 2842 | { | ||
3809 | 2843 | // we're adding to an array here | ||
3810 | 2844 | $this->me['array'] = array_merge($this->me['array'], $vals); | ||
3811 | 2845 | return 1; | ||
3812 | 2846 | } | ||
3813 | 2847 | else | ||
3814 | 2848 | { | ||
3815 | 2849 | error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']'); | ||
3816 | 2850 | return 0; | ||
3817 | 2851 | } | ||
3818 | 2852 | } | ||
3819 | 2853 | |||
3820 | 2854 | /** | ||
3821 | 2855 | * Add an array of named xmlrpcval objects to an xmlrpcval | ||
3822 | 2856 | * @param array $vals | ||
3823 | 2857 | * @return int 1 or 0 on failure | ||
3824 | 2858 | * @access public | ||
3825 | 2859 | * | ||
3826 | 2860 | * @todo add some checking for $vals to be an array? | ||
3827 | 2861 | */ | ||
3828 | 2862 | function addStruct($vals) | ||
3829 | 2863 | { | ||
3830 | 2864 | if($this->mytype==0) | ||
3831 | 2865 | { | ||
3832 | 2866 | $this->mytype=$GLOBALS['xmlrpcTypes']['struct']; | ||
3833 | 2867 | $this->me['struct']=$vals; | ||
3834 | 2868 | return 1; | ||
3835 | 2869 | } | ||
3836 | 2870 | elseif($this->mytype==3) | ||
3837 | 2871 | { | ||
3838 | 2872 | // we're adding to a struct here | ||
3839 | 2873 | $this->me['struct'] = array_merge($this->me['struct'], $vals); | ||
3840 | 2874 | return 1; | ||
3841 | 2875 | } | ||
3842 | 2876 | else | ||
3843 | 2877 | { | ||
3844 | 2878 | error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']'); | ||
3845 | 2879 | return 0; | ||
3846 | 2880 | } | ||
3847 | 2881 | } | ||
3848 | 2882 | |||
3849 | 2883 | // poor man's version of print_r ??? | ||
3850 | 2884 | // DEPRECATED! | ||
3851 | 2885 | function dump($ar) | ||
3852 | 2886 | { | ||
3853 | 2887 | foreach($ar as $key => $val) | ||
3854 | 2888 | { | ||
3855 | 2889 | echo "$key => $val<br />"; | ||
3856 | 2890 | if($key == 'array') | ||
3857 | 2891 | { | ||
3858 | 2892 | while(list($key2, $val2) = each($val)) | ||
3859 | 2893 | { | ||
3860 | 2894 | echo "-- $key2 => $val2<br />"; | ||
3861 | 2895 | } | ||
3862 | 2896 | } | ||
3863 | 2897 | } | ||
3864 | 2898 | } | ||
3865 | 2899 | |||
3866 | 2900 | /** | ||
3867 | 2901 | * Returns a string containing "struct", "array" or "scalar" describing the base type of the value | ||
3868 | 2902 | * @return string | ||
3869 | 2903 | * @access public | ||
3870 | 2904 | */ | ||
3871 | 2905 | function kindOf() | ||
3872 | 2906 | { | ||
3873 | 2907 | switch($this->mytype) | ||
3874 | 2908 | { | ||
3875 | 2909 | case 3: | ||
3876 | 2910 | return 'struct'; | ||
3877 | 2911 | break; | ||
3878 | 2912 | case 2: | ||
3879 | 2913 | return 'array'; | ||
3880 | 2914 | break; | ||
3881 | 2915 | case 1: | ||
3882 | 2916 | return 'scalar'; | ||
3883 | 2917 | break; | ||
3884 | 2918 | default: | ||
3885 | 2919 | return 'undef'; | ||
3886 | 2920 | } | ||
3887 | 2921 | } | ||
3888 | 2922 | |||
3889 | 2923 | /** | ||
3890 | 2924 | * @access private | ||
3891 | 2925 | */ | ||
3892 | 2926 | function serializedata($typ, $val, $charset_encoding='') | ||
3893 | 2927 | { | ||
3894 | 2928 | $rs=''; | ||
3895 | 2929 | switch(@$GLOBALS['xmlrpcTypes'][$typ]) | ||
3896 | 2930 | { | ||
3897 | 2931 | case 1: | ||
3898 | 2932 | switch($typ) | ||
3899 | 2933 | { | ||
3900 | 2934 | case $GLOBALS['xmlrpcBase64']: | ||
3901 | 2935 | $rs.="<${typ}>" . base64_encode($val) . "</${typ}>"; | ||
3902 | 2936 | break; | ||
3903 | 2937 | case $GLOBALS['xmlrpcBoolean']: | ||
3904 | 2938 | $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>"; | ||
3905 | 2939 | break; | ||
3906 | 2940 | case $GLOBALS['xmlrpcString']: | ||
3907 | 2941 | // G. Giunta 2005/2/13: do NOT use htmlentities, since | ||
3908 | 2942 | // it will produce named html entities, which are invalid xml | ||
3909 | 2943 | $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding). "</${typ}>"; | ||
3910 | 2944 | break; | ||
3911 | 2945 | case $GLOBALS['xmlrpcInt']: | ||
3912 | 2946 | case $GLOBALS['xmlrpcI4']: | ||
3913 | 2947 | $rs.="<${typ}>".(int)$val."</${typ}>"; | ||
3914 | 2948 | break; | ||
3915 | 2949 | case $GLOBALS['xmlrpcDouble']: | ||
3916 | 2950 | // avoid using standard conversion of float to string because it is locale-dependent, | ||
3917 | 2951 | // and also because the xmlrpc spec forbids exponential notation. | ||
3918 | 2952 | // sprintf('%F') could be most likely ok but it fails eg. on 2e-14. | ||
3919 | 2953 | // The code below tries its best at keeping max precision while avoiding exp notation, | ||
3920 | 2954 | // but there is of course no limit in the number of decimal places to be used... | ||
3921 | 2955 | $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."</${typ}>"; | ||
3922 | 2956 | break; | ||
3923 | 2957 | case $GLOBALS['xmlrpcDateTime']: | ||
3924 | 2958 | if (is_string($val)) | ||
3925 | 2959 | { | ||
3926 | 2960 | $rs.="<${typ}>${val}</${typ}>"; | ||
3927 | 2961 | } | ||
3928 | 2962 | else if(is_a($val, 'DateTime')) | ||
3929 | 2963 | { | ||
3930 | 2964 | $rs.="<${typ}>".$val->format('Ymd\TH:i:s')."</${typ}>"; | ||
3931 | 2965 | } | ||
3932 | 2966 | else if(is_int($val)) | ||
3933 | 2967 | { | ||
3934 | 2968 | $rs.="<${typ}>".strftime("%Y%m%dT%H:%M:%S", $val)."</${typ}>"; | ||
3935 | 2969 | } | ||
3936 | 2970 | else | ||
3937 | 2971 | { | ||
3938 | 2972 | // not really a good idea here: but what shall we output anyway? left for backward compat... | ||
3939 | 2973 | $rs.="<${typ}>${val}</${typ}>"; | ||
3940 | 2974 | } | ||
3941 | 2975 | break; | ||
3942 | 2976 | case $GLOBALS['xmlrpcNull']: | ||
3943 | 2977 | if ($GLOBALS['xmlrpc_null_apache_encoding']) | ||
3944 | 2978 | { | ||
3945 | 2979 | $rs.="<ex:nil/>"; | ||
3946 | 2980 | } | ||
3947 | 2981 | else | ||
3948 | 2982 | { | ||
3949 | 2983 | $rs.="<nil/>"; | ||
3950 | 2984 | } | ||
3951 | 2985 | break; | ||
3952 | 2986 | default: | ||
3953 | 2987 | // no standard type value should arrive here, but provide a possibility | ||
3954 | 2988 | // for xmlrpcvals of unknown type... | ||
3955 | 2989 | $rs.="<${typ}>${val}</${typ}>"; | ||
3956 | 2990 | } | ||
3957 | 2991 | break; | ||
3958 | 2992 | case 3: | ||
3959 | 2993 | // struct | ||
3960 | 2994 | if ($this->_php_class) | ||
3961 | 2995 | { | ||
3962 | 2996 | $rs.='<struct php_class="' . $this->_php_class . "\">\n"; | ||
3963 | 2997 | } | ||
3964 | 2998 | else | ||
3965 | 2999 | { | ||
3966 | 3000 | $rs.="<struct>\n"; | ||
3967 | 3001 | } | ||
3968 | 3002 | foreach($val as $key2 => $val2) | ||
3969 | 3003 | { | ||
3970 | 3004 | $rs.='<member><name>'.xmlrpc_encode_entitites($key2, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding)."</name>\n"; | ||
3971 | 3005 | //$rs.=$this->serializeval($val2); | ||
3972 | 3006 | $rs.=$val2->serialize($charset_encoding); | ||
3973 | 3007 | $rs.="</member>\n"; | ||
3974 | 3008 | } | ||
3975 | 3009 | $rs.='</struct>'; | ||
3976 | 3010 | break; | ||
3977 | 3011 | case 2: | ||
3978 | 3012 | // array | ||
3979 | 3013 | $rs.="<array>\n<data>\n"; | ||
3980 | 3014 | for($i=0; $i<count($val); $i++) | ||
3981 | 3015 | { | ||
3982 | 3016 | //$rs.=$this->serializeval($val[$i]); | ||
3983 | 3017 | $rs.=$val[$i]->serialize($charset_encoding); | ||
3984 | 3018 | } | ||
3985 | 3019 | $rs.="</data>\n</array>"; | ||
3986 | 3020 | break; | ||
3987 | 3021 | default: | ||
3988 | 3022 | break; | ||
3989 | 3023 | } | ||
3990 | 3024 | return $rs; | ||
3991 | 3025 | } | ||
3992 | 3026 | |||
3993 | 3027 | /** | ||
3994 | 3028 | * Returns xml representation of the value. XML prologue not included | ||
3995 | 3029 | * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed | ||
3996 | 3030 | * @return string | ||
3997 | 3031 | * @access public | ||
3998 | 3032 | */ | ||
3999 | 3033 | function serialize($charset_encoding='') | ||
4000 | 3034 | { | ||
4001 | 3035 | // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals... | ||
4002 | 3036 | //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval'))) | ||
4003 | 3037 | //{ | ||
4004 | 3038 | reset($this->me); | ||
4005 | 3039 | list($typ, $val) = each($this->me); | ||
4006 | 3040 | return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n"; | ||
4007 | 3041 | //} | ||
4008 | 3042 | } | ||
4009 | 3043 | |||
4010 | 3044 | // DEPRECATED | ||
4011 | 3045 | function serializeval($o) | ||
4012 | 3046 | { | ||
4013 | 3047 | // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals... | ||
4014 | 3048 | //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval'))) | ||
4015 | 3049 | //{ | ||
4016 | 3050 | $ar=$o->me; | ||
4017 | 3051 | reset($ar); | ||
4018 | 3052 | list($typ, $val) = each($ar); | ||
4019 | 3053 | return '<value>' . $this->serializedata($typ, $val) . "</value>\n"; | ||
4020 | 3054 | //} | ||
4021 | 3055 | } | ||
4022 | 3056 | |||
4023 | 3057 | /** | ||
4024 | 3058 | * Checks wheter a struct member with a given name is present. | ||
4025 | 3059 | * Works only on xmlrpcvals of type struct. | ||
4026 | 3060 | * @param string $m the name of the struct member to be looked up | ||
4027 | 3061 | * @return boolean | ||
4028 | 3062 | * @access public | ||
4029 | 3063 | */ | ||
4030 | 3064 | function structmemexists($m) | ||
4031 | 3065 | { | ||
4032 | 3066 | return array_key_exists($m, $this->me['struct']); | ||
4033 | 3067 | } | ||
4034 | 3068 | |||
4035 | 3069 | /** | ||
4036 | 3070 | * Returns the value of a given struct member (an xmlrpcval object in itself). | ||
4037 | 3071 | * Will raise a php warning if struct member of given name does not exist | ||
4038 | 3072 | * @param string $m the name of the struct member to be looked up | ||
4039 | 3073 | * @return xmlrpcval | ||
4040 | 3074 | * @access public | ||
4041 | 3075 | */ | ||
4042 | 3076 | function structmem($m) | ||
4043 | 3077 | { | ||
4044 | 3078 | return $this->me['struct'][$m]; | ||
4045 | 3079 | } | ||
4046 | 3080 | |||
4047 | 3081 | /** | ||
4048 | 3082 | * Reset internal pointer for xmlrpcvals of type struct. | ||
4049 | 3083 | * @access public | ||
4050 | 3084 | */ | ||
4051 | 3085 | function structreset() | ||
4052 | 3086 | { | ||
4053 | 3087 | reset($this->me['struct']); | ||
4054 | 3088 | } | ||
4055 | 3089 | |||
4056 | 3090 | /** | ||
4057 | 3091 | * Return next member element for xmlrpcvals of type struct. | ||
4058 | 3092 | * @return xmlrpcval | ||
4059 | 3093 | * @access public | ||
4060 | 3094 | */ | ||
4061 | 3095 | function structeach() | ||
4062 | 3096 | { | ||
4063 | 3097 | return each($this->me['struct']); | ||
4064 | 3098 | } | ||
4065 | 3099 | |||
4066 | 3100 | // DEPRECATED! this code looks like it is very fragile and has not been fixed | ||
4067 | 3101 | // for a long long time. Shall we remove it for 2.0? | ||
4068 | 3102 | function getval() | ||
4069 | 3103 | { | ||
4070 | 3104 | // UNSTABLE | ||
4071 | 3105 | reset($this->me); | ||
4072 | 3106 | list($a,$b)=each($this->me); | ||
4073 | 3107 | // contributed by I Sofer, 2001-03-24 | ||
4074 | 3108 | // add support for nested arrays to scalarval | ||
4075 | 3109 | // i've created a new method here, so as to | ||
4076 | 3110 | // preserve back compatibility | ||
4077 | 3111 | |||
4078 | 3112 | if(is_array($b)) | ||
4079 | 3113 | { | ||
4080 | 3114 | @reset($b); | ||
4081 | 3115 | while(list($id,$cont) = @each($b)) | ||
4082 | 3116 | { | ||
4083 | 3117 | $b[$id] = $cont->scalarval(); | ||
4084 | 3118 | } | ||
4085 | 3119 | } | ||
4086 | 3120 | |||
4087 | 3121 | // add support for structures directly encoding php objects | ||
4088 | 3122 | if(is_object($b)) | ||
4089 | 3123 | { | ||
4090 | 3124 | $t = get_object_vars($b); | ||
4091 | 3125 | @reset($t); | ||
4092 | 3126 | while(list($id,$cont) = @each($t)) | ||
4093 | 3127 | { | ||
4094 | 3128 | $t[$id] = $cont->scalarval(); | ||
4095 | 3129 | } | ||
4096 | 3130 | @reset($t); | ||
4097 | 3131 | while(list($id,$cont) = @each($t)) | ||
4098 | 3132 | { | ||
4099 | 3133 | @$b->$id = $cont; | ||
4100 | 3134 | } | ||
4101 | 3135 | } | ||
4102 | 3136 | // end contrib | ||
4103 | 3137 | return $b; | ||
4104 | 3138 | } | ||
4105 | 3139 | |||
4106 | 3140 | /** | ||
4107 | 3141 | * Returns the value of a scalar xmlrpcval | ||
4108 | 3142 | * @return mixed | ||
4109 | 3143 | * @access public | ||
4110 | 3144 | */ | ||
4111 | 3145 | function scalarval() | ||
4112 | 3146 | { | ||
4113 | 3147 | reset($this->me); | ||
4114 | 3148 | list(,$b)=each($this->me); | ||
4115 | 3149 | return $b; | ||
4116 | 3150 | } | ||
4117 | 3151 | |||
4118 | 3152 | /** | ||
4119 | 3153 | * Returns the type of the xmlrpcval. | ||
4120 | 3154 | * For integers, 'int' is always returned in place of 'i4' | ||
4121 | 3155 | * @return string | ||
4122 | 3156 | * @access public | ||
4123 | 3157 | */ | ||
4124 | 3158 | function scalartyp() | ||
4125 | 3159 | { | ||
4126 | 3160 | reset($this->me); | ||
4127 | 3161 | list($a,)=each($this->me); | ||
4128 | 3162 | if($a==$GLOBALS['xmlrpcI4']) | ||
4129 | 3163 | { | ||
4130 | 3164 | $a=$GLOBALS['xmlrpcInt']; | ||
4131 | 3165 | } | ||
4132 | 3166 | return $a; | ||
4133 | 3167 | } | ||
4134 | 3168 | |||
4135 | 3169 | /** | ||
4136 | 3170 | * Returns the m-th member of an xmlrpcval of struct type | ||
4137 | 3171 | * @param integer $m the index of the value to be retrieved (zero based) | ||
4138 | 3172 | * @return xmlrpcval | ||
4139 | 3173 | * @access public | ||
4140 | 3174 | */ | ||
4141 | 3175 | function arraymem($m) | ||
4142 | 3176 | { | ||
4143 | 3177 | return $this->me['array'][$m]; | ||
4144 | 3178 | } | ||
4145 | 3179 | |||
4146 | 3180 | /** | ||
4147 | 3181 | * Returns the number of members in an xmlrpcval of array type | ||
4148 | 3182 | * @return integer | ||
4149 | 3183 | * @access public | ||
4150 | 3184 | */ | ||
4151 | 3185 | function arraysize() | ||
4152 | 3186 | { | ||
4153 | 3187 | return count($this->me['array']); | ||
4154 | 3188 | } | ||
4155 | 3189 | |||
4156 | 3190 | /** | ||
4157 | 3191 | * Returns the number of members in an xmlrpcval of struct type | ||
4158 | 3192 | * @return integer | ||
4159 | 3193 | * @access public | ||
4160 | 3194 | */ | ||
4161 | 3195 | function structsize() | ||
4162 | 3196 | { | ||
4163 | 3197 | return count($this->me['struct']); | ||
4164 | 3198 | } | ||
4165 | 3199 | } | ||
4166 | 3200 | |||
4167 | 3201 | |||
4168 | 3202 | // date helpers | ||
4169 | 3203 | |||
4170 | 3204 | /** | ||
4171 | 3205 | * Given a timestamp, return the corresponding ISO8601 encoded string. | ||
4172 | 3206 | * | ||
4173 | 3207 | * Really, timezones ought to be supported | ||
4174 | 3208 | * but the XML-RPC spec says: | ||
4175 | 3209 | * | ||
4176 | 3210 | * "Don't assume a timezone. It should be specified by the server in its | ||
4177 | 3211 | * documentation what assumptions it makes about timezones." | ||
4178 | 3212 | * | ||
4179 | 3213 | * These routines always assume localtime unless | ||
4180 | 3214 | * $utc is set to 1, in which case UTC is assumed | ||
4181 | 3215 | * and an adjustment for locale is made when encoding | ||
4182 | 3216 | * | ||
4183 | 3217 | * @param int $timet (timestamp) | ||
4184 | 3218 | * @param int $utc (0 or 1) | ||
4185 | 3219 | * @return string | ||
4186 | 3220 | */ | ||
4187 | 3221 | function iso8601_encode($timet, $utc=0) | ||
4188 | 3222 | { | ||
4189 | 3223 | if(!$utc) | ||
4190 | 3224 | { | ||
4191 | 3225 | $t=strftime("%Y%m%dT%H:%M:%S", $timet); | ||
4192 | 3226 | } | ||
4193 | 3227 | else | ||
4194 | 3228 | { | ||
4195 | 3229 | if(function_exists('gmstrftime')) | ||
4196 | 3230 | { | ||
4197 | 3231 | // gmstrftime doesn't exist in some versions | ||
4198 | 3232 | // of PHP | ||
4199 | 3233 | $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet); | ||
4200 | 3234 | } | ||
4201 | 3235 | else | ||
4202 | 3236 | { | ||
4203 | 3237 | $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z')); | ||
4204 | 3238 | } | ||
4205 | 3239 | } | ||
4206 | 3240 | return $t; | ||
4207 | 3241 | } | ||
4208 | 3242 | |||
4209 | 3243 | /** | ||
4210 | 3244 | * Given an ISO8601 date string, return a timet in the localtime, or UTC | ||
4211 | 3245 | * @param string $idate | ||
4212 | 3246 | * @param int $utc either 0 or 1 | ||
4213 | 3247 | * @return int (datetime) | ||
4214 | 3248 | */ | ||
4215 | 3249 | function iso8601_decode($idate, $utc=0) | ||
4216 | 3250 | { | ||
4217 | 3251 | $t=0; | ||
4218 | 3252 | if(preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $idate, $regs)) | ||
4219 | 3253 | { | ||
4220 | 3254 | if($utc) | ||
4221 | 3255 | { | ||
4222 | 3256 | $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); | ||
4223 | 3257 | } | ||
4224 | 3258 | else | ||
4225 | 3259 | { | ||
4226 | 3260 | $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); | ||
4227 | 3261 | } | ||
4228 | 3262 | } | ||
4229 | 3263 | return $t; | ||
4230 | 3264 | } | ||
4231 | 3265 | |||
4232 | 3266 | /** | ||
4233 | 3267 | * Takes an xmlrpc value in PHP xmlrpcval object format and translates it into native PHP types. | ||
4234 | 3268 | * | ||
4235 | 3269 | * Works with xmlrpc message objects as input, too. | ||
4236 | 3270 | * | ||
4237 | 3271 | * Given proper options parameter, can rebuild generic php object instances | ||
4238 | 3272 | * (provided those have been encoded to xmlrpc format using a corresponding | ||
4239 | 3273 | * option in php_xmlrpc_encode()) | ||
4240 | 3274 | * PLEASE NOTE that rebuilding php objects involves calling their constructor function. | ||
4241 | 3275 | * This means that the remote communication end can decide which php code will | ||
4242 | 3276 | * get executed on your server, leaving the door possibly open to 'php-injection' | ||
4243 | 3277 | * style of attacks (provided you have some classes defined on your server that | ||
4244 | 3278 | * might wreak havoc if instances are built outside an appropriate context). | ||
4245 | 3279 | * Make sure you trust the remote server/client before eanbling this! | ||
4246 | 3280 | * | ||
4247 | 3281 | * @author Dan Libby (dan@libby.com) | ||
4248 | 3282 | * | ||
4249 | 3283 | * @param xmlrpcval $xmlrpc_val | ||
4250 | 3284 | * @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects; if 'dates_as_objects' is set xmlrpc datetimes are decoded as php DateTime objects (standard is | ||
4251 | 3285 | * @return mixed | ||
4252 | 3286 | */ | ||
4253 | 3287 | function php_xmlrpc_decode($xmlrpc_val, $options=array()) | ||
4254 | 3288 | { | ||
4255 | 3289 | switch($xmlrpc_val->kindOf()) | ||
4256 | 3290 | { | ||
4257 | 3291 | case 'scalar': | ||
4258 | 3292 | if (in_array('extension_api', $options)) | ||
4259 | 3293 | { | ||
4260 | 3294 | reset($xmlrpc_val->me); | ||
4261 | 3295 | list($typ,$val) = each($xmlrpc_val->me); | ||
4262 | 3296 | switch ($typ) | ||
4263 | 3297 | { | ||
4264 | 3298 | case 'dateTime.iso8601': | ||
4265 | 3299 | $xmlrpc_val->scalar = $val; | ||
4266 | 3300 | $xmlrpc_val->xmlrpc_type = 'datetime'; | ||
4267 | 3301 | $xmlrpc_val->timestamp = iso8601_decode($val); | ||
4268 | 3302 | return $xmlrpc_val; | ||
4269 | 3303 | case 'base64': | ||
4270 | 3304 | $xmlrpc_val->scalar = $val; | ||
4271 | 3305 | $xmlrpc_val->type = $typ; | ||
4272 | 3306 | return $xmlrpc_val; | ||
4273 | 3307 | default: | ||
4274 | 3308 | return $xmlrpc_val->scalarval(); | ||
4275 | 3309 | } | ||
4276 | 3310 | } | ||
4277 | 3311 | if (in_array('dates_as_objects', $options) && $xmlrpc_val->scalartyp() == 'dateTime.iso8601') | ||
4278 | 3312 | { | ||
4279 | 3313 | // we return a Datetime object instead of a string | ||
4280 | 3314 | // since now the constructor of xmlrpcval accepts safely strings, ints and datetimes, | ||
4281 | 3315 | // we cater to all 3 cases here | ||
4282 | 3316 | $out = $xmlrpc_val->scalarval(); | ||
4283 | 3317 | if (is_string($out)) | ||
4284 | 3318 | { | ||
4285 | 3319 | $out = strtotime($out); | ||
4286 | 3320 | } | ||
4287 | 3321 | if (is_int($out)) | ||
4288 | 3322 | { | ||
4289 | 3323 | $result = new Datetime(); | ||
4290 | 3324 | $result->setTimestamp($out); | ||
4291 | 3325 | return $result; | ||
4292 | 3326 | } | ||
4293 | 3327 | elseif (is_a($out, 'Datetime')) | ||
4294 | 3328 | { | ||
4295 | 3329 | return $out; | ||
4296 | 3330 | } | ||
4297 | 3331 | } | ||
4298 | 3332 | return $xmlrpc_val->scalarval(); | ||
4299 | 3333 | case 'array': | ||
4300 | 3334 | $size = $xmlrpc_val->arraysize(); | ||
4301 | 3335 | $arr = array(); | ||
4302 | 3336 | for($i = 0; $i < $size; $i++) | ||
4303 | 3337 | { | ||
4304 | 3338 | $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i), $options); | ||
4305 | 3339 | } | ||
4306 | 3340 | return $arr; | ||
4307 | 3341 | case 'struct': | ||
4308 | 3342 | $xmlrpc_val->structreset(); | ||
4309 | 3343 | // If user said so, try to rebuild php objects for specific struct vals. | ||
4310 | 3344 | /// @todo should we raise a warning for class not found? | ||
4311 | 3345 | // shall we check for proper subclass of xmlrpcval instead of | ||
4312 | 3346 | // presence of _php_class to detect what we can do? | ||
4313 | 3347 | if (in_array('decode_php_objs', $options) && $xmlrpc_val->_php_class != '' | ||
4314 | 3348 | && class_exists($xmlrpc_val->_php_class)) | ||
4315 | 3349 | { | ||
4316 | 3350 | $obj = @new $xmlrpc_val->_php_class; | ||
4317 | 3351 | while(list($key,$value)=$xmlrpc_val->structeach()) | ||
4318 | 3352 | { | ||
4319 | 3353 | $obj->$key = php_xmlrpc_decode($value, $options); | ||
4320 | 3354 | } | ||
4321 | 3355 | return $obj; | ||
4322 | 3356 | } | ||
4323 | 3357 | else | ||
4324 | 3358 | { | ||
4325 | 3359 | $arr = array(); | ||
4326 | 3360 | while(list($key,$value)=$xmlrpc_val->structeach()) | ||
4327 | 3361 | { | ||
4328 | 3362 | $arr[$key] = php_xmlrpc_decode($value, $options); | ||
4329 | 3363 | } | ||
4330 | 3364 | return $arr; | ||
4331 | 3365 | } | ||
4332 | 3366 | case 'msg': | ||
4333 | 3367 | $paramcount = $xmlrpc_val->getNumParams(); | ||
4334 | 3368 | $arr = array(); | ||
4335 | 3369 | for($i = 0; $i < $paramcount; $i++) | ||
4336 | 3370 | { | ||
4337 | 3371 | $arr[] = php_xmlrpc_decode($xmlrpc_val->getParam($i)); | ||
4338 | 3372 | } | ||
4339 | 3373 | return $arr; | ||
4340 | 3374 | } | ||
4341 | 3375 | } | ||
4342 | 3376 | |||
4343 | 3377 | // This constant left here only for historical reasons... | ||
4344 | 3378 | // it was used to decide if we have to define xmlrpc_encode on our own, but | ||
4345 | 3379 | // we do not do it anymore | ||
4346 | 3380 | if(function_exists('xmlrpc_decode')) | ||
4347 | 3381 | { | ||
4348 | 3382 | define('XMLRPC_EPI_ENABLED','1'); | ||
4349 | 3383 | } | ||
4350 | 3384 | else | ||
4351 | 3385 | { | ||
4352 | 3386 | define('XMLRPC_EPI_ENABLED','0'); | ||
4353 | 3387 | } | ||
4354 | 3388 | |||
4355 | 3389 | /** | ||
4356 | 3390 | * Takes native php types and encodes them into xmlrpc PHP object format. | ||
4357 | 3391 | * It will not re-encode xmlrpcval objects. | ||
4358 | 3392 | * | ||
4359 | 3393 | * Feature creep -- could support more types via optional type argument | ||
4360 | 3394 | * (string => datetime support has been added, ??? => base64 not yet) | ||
4361 | 3395 | * | ||
4362 | 3396 | * If given a proper options parameter, php object instances will be encoded | ||
4363 | 3397 | * into 'special' xmlrpc values, that can later be decoded into php objects | ||
4364 | 3398 | * by calling php_xmlrpc_decode() with a corresponding option | ||
4365 | 3399 | * | ||
4366 | 3400 | * @author Dan Libby (dan@libby.com) | ||
4367 | 3401 | * | ||
4368 | 3402 | * @param mixed $php_val the value to be converted into an xmlrpcval object | ||
4369 | 3403 | * @param array $options can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api' | ||
4370 | 3404 | * @return xmlrpcval | ||
4371 | 3405 | */ | ||
4372 | 3406 | function php_xmlrpc_encode($php_val, $options=array()) | ||
4373 | 3407 | { | ||
4374 | 3408 | $type = gettype($php_val); | ||
4375 | 3409 | switch($type) | ||
4376 | 3410 | { | ||
4377 | 3411 | case 'string': | ||
4378 | 3412 | if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val)) | ||
4379 | 3413 | $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']); | ||
4380 | 3414 | else | ||
4381 | 3415 | $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcString']); | ||
4382 | 3416 | break; | ||
4383 | 3417 | case 'integer': | ||
4384 | 3418 | $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']); | ||
4385 | 3419 | break; | ||
4386 | 3420 | case 'double': | ||
4387 | 3421 | $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']); | ||
4388 | 3422 | break; | ||
4389 | 3423 | // <G_Giunta_2001-02-29> | ||
4390 | 3424 | // Add support for encoding/decoding of booleans, since they are supported in PHP | ||
4391 | 3425 | case 'boolean': | ||
4392 | 3426 | $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']); | ||
4393 | 3427 | break; | ||
4394 | 3428 | // </G_Giunta_2001-02-29> | ||
4395 | 3429 | case 'array': | ||
4396 | 3430 | // PHP arrays can be encoded to either xmlrpc structs or arrays, | ||
4397 | 3431 | // depending on wheter they are hashes or plain 0..n integer indexed | ||
4398 | 3432 | // A shorter one-liner would be | ||
4399 | 3433 | // $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); | ||
4400 | 3434 | // but execution time skyrockets! | ||
4401 | 3435 | $j = 0; | ||
4402 | 3436 | $arr = array(); | ||
4403 | 3437 | $ko = false; | ||
4404 | 3438 | foreach($php_val as $key => $val) | ||
4405 | 3439 | { | ||
4406 | 3440 | $arr[$key] = php_xmlrpc_encode($val, $options); | ||
4407 | 3441 | if(!$ko && $key !== $j) | ||
4408 | 3442 | { | ||
4409 | 3443 | $ko = true; | ||
4410 | 3444 | } | ||
4411 | 3445 | $j++; | ||
4412 | 3446 | } | ||
4413 | 3447 | if($ko) | ||
4414 | 3448 | { | ||
4415 | 3449 | $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); | ||
4416 | 3450 | } | ||
4417 | 3451 | else | ||
4418 | 3452 | { | ||
4419 | 3453 | $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcArray']); | ||
4420 | 3454 | } | ||
4421 | 3455 | break; | ||
4422 | 3456 | case 'object': | ||
4423 | 3457 | if(is_a($php_val, 'xmlrpcval')) | ||
4424 | 3458 | { | ||
4425 | 3459 | $xmlrpc_val = $php_val; | ||
4426 | 3460 | } | ||
4427 | 3461 | else if(is_a($php_val, 'DateTime')) | ||
4428 | 3462 | { | ||
4429 | 3463 | $xmlrpc_val = new xmlrpcval($php_val->format('Ymd\TH:i:s'), $GLOBALS['xmlrpcStruct']); | ||
4430 | 3464 | } | ||
4431 | 3465 | else | ||
4432 | 3466 | { | ||
4433 | 3467 | $arr = array(); | ||
4434 | 3468 | reset($php_val); | ||
4435 | 3469 | while(list($k,$v) = each($php_val)) | ||
4436 | 3470 | { | ||
4437 | 3471 | $arr[$k] = php_xmlrpc_encode($v, $options); | ||
4438 | 3472 | } | ||
4439 | 3473 | $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); | ||
4440 | 3474 | if (in_array('encode_php_objs', $options)) | ||
4441 | 3475 | { | ||
4442 | 3476 | // let's save original class name into xmlrpcval: | ||
4443 | 3477 | // might be useful later on... | ||
4444 | 3478 | $xmlrpc_val->_php_class = get_class($php_val); | ||
4445 | 3479 | } | ||
4446 | 3480 | } | ||
4447 | 3481 | break; | ||
4448 | 3482 | case 'NULL': | ||
4449 | 3483 | if (in_array('extension_api', $options)) | ||
4450 | 3484 | { | ||
4451 | 3485 | $xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcString']); | ||
4452 | 3486 | } | ||
4453 | 3487 | else if (in_array('null_extension', $options)) | ||
4454 | 3488 | { | ||
4455 | 3489 | $xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcNull']); | ||
4456 | 3490 | } | ||
4457 | 3491 | else | ||
4458 | 3492 | { | ||
4459 | 3493 | $xmlrpc_val = new xmlrpcval(); | ||
4460 | 3494 | } | ||
4461 | 3495 | break; | ||
4462 | 3496 | case 'resource': | ||
4463 | 3497 | if (in_array('extension_api', $options)) | ||
4464 | 3498 | { | ||
4465 | 3499 | $xmlrpc_val = new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']); | ||
4466 | 3500 | } | ||
4467 | 3501 | else | ||
4468 | 3502 | { | ||
4469 | 3503 | $xmlrpc_val = new xmlrpcval(); | ||
4470 | 3504 | } | ||
4471 | 3505 | // catch "user function", "unknown type" | ||
4472 | 3506 | default: | ||
4473 | 3507 | // giancarlo pinerolo <ping@alt.it> | ||
4474 | 3508 | // it has to return | ||
4475 | 3509 | // an empty object in case, not a boolean. | ||
4476 | 3510 | $xmlrpc_val = new xmlrpcval(); | ||
4477 | 3511 | break; | ||
4478 | 3512 | } | ||
4479 | 3513 | return $xmlrpc_val; | ||
4480 | 3514 | } | ||
4481 | 3515 | |||
4482 | 3516 | /** | ||
4483 | 3517 | * Convert the xml representation of a method response, method request or single | ||
4484 | 3518 | * xmlrpc value into the appropriate object (a.k.a. deserialize) | ||
4485 | 3519 | * @param string $xml_val | ||
4486 | 3520 | * @param array $options | ||
4487 | 3521 | * @return mixed false on error, or an instance of either xmlrpcval, xmlrpcmsg or xmlrpcresp | ||
4488 | 3522 | */ | ||
4489 | 3523 | function php_xmlrpc_decode_xml($xml_val, $options=array()) | ||
4490 | 3524 | { | ||
4491 | 3525 | $GLOBALS['_xh'] = array(); | ||
4492 | 3526 | $GLOBALS['_xh']['ac'] = ''; | ||
4493 | 3527 | $GLOBALS['_xh']['stack'] = array(); | ||
4494 | 3528 | $GLOBALS['_xh']['valuestack'] = array(); | ||
4495 | 3529 | $GLOBALS['_xh']['params'] = array(); | ||
4496 | 3530 | $GLOBALS['_xh']['pt'] = array(); | ||
4497 | 3531 | $GLOBALS['_xh']['isf'] = 0; | ||
4498 | 3532 | $GLOBALS['_xh']['isf_reason'] = ''; | ||
4499 | 3533 | $GLOBALS['_xh']['method'] = false; | ||
4500 | 3534 | $GLOBALS['_xh']['rt'] = ''; | ||
4501 | 3535 | /// @todo 'guestimate' encoding | ||
4502 | 3536 | $parser = xml_parser_create(); | ||
4503 | 3537 | xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); | ||
4504 | 3538 | // What if internal encoding is not in one of the 3 allowed? | ||
4505 | 3539 | // we use the broadest one, ie. utf8! | ||
4506 | 3540 | if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) | ||
4507 | 3541 | { | ||
4508 | 3542 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); | ||
4509 | 3543 | } | ||
4510 | 3544 | else | ||
4511 | 3545 | { | ||
4512 | 3546 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); | ||
4513 | 3547 | } | ||
4514 | 3548 | xml_set_element_handler($parser, 'xmlrpc_se_any', 'xmlrpc_ee'); | ||
4515 | 3549 | xml_set_character_data_handler($parser, 'xmlrpc_cd'); | ||
4516 | 3550 | xml_set_default_handler($parser, 'xmlrpc_dh'); | ||
4517 | 3551 | if(!xml_parse($parser, $xml_val, 1)) | ||
4518 | 3552 | { | ||
4519 | 3553 | $errstr = sprintf('XML error: %s at line %d, column %d', | ||
4520 | 3554 | xml_error_string(xml_get_error_code($parser)), | ||
4521 | 3555 | xml_get_current_line_number($parser), xml_get_current_column_number($parser)); | ||
4522 | 3556 | error_log($errstr); | ||
4523 | 3557 | xml_parser_free($parser); | ||
4524 | 3558 | return false; | ||
4525 | 3559 | } | ||
4526 | 3560 | xml_parser_free($parser); | ||
4527 | 3561 | if ($GLOBALS['_xh']['isf'] > 1) // test that $GLOBALS['_xh']['value'] is an obj, too??? | ||
4528 | 3562 | { | ||
4529 | 3563 | error_log($GLOBALS['_xh']['isf_reason']); | ||
4530 | 3564 | return false; | ||
4531 | 3565 | } | ||
4532 | 3566 | switch ($GLOBALS['_xh']['rt']) | ||
4533 | 3567 | { | ||
4534 | 3568 | case 'methodresponse': | ||
4535 | 3569 | $v =& $GLOBALS['_xh']['value']; | ||
4536 | 3570 | if ($GLOBALS['_xh']['isf'] == 1) | ||
4537 | 3571 | { | ||
4538 | 3572 | $vc = $v->structmem('faultCode'); | ||
4539 | 3573 | $vs = $v->structmem('faultString'); | ||
4540 | 3574 | $r = new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval()); | ||
4541 | 3575 | } | ||
4542 | 3576 | else | ||
4543 | 3577 | { | ||
4544 | 3578 | $r = new xmlrpcresp($v); | ||
4545 | 3579 | } | ||
4546 | 3580 | return $r; | ||
4547 | 3581 | case 'methodcall': | ||
4548 | 3582 | $m = new xmlrpcmsg($GLOBALS['_xh']['method']); | ||
4549 | 3583 | for($i=0; $i < count($GLOBALS['_xh']['params']); $i++) | ||
4550 | 3584 | { | ||
4551 | 3585 | $m->addParam($GLOBALS['_xh']['params'][$i]); | ||
4552 | 3586 | } | ||
4553 | 3587 | return $m; | ||
4554 | 3588 | case 'value': | ||
4555 | 3589 | return $GLOBALS['_xh']['value']; | ||
4556 | 3590 | default: | ||
4557 | 3591 | return false; | ||
4558 | 3592 | } | ||
4559 | 3593 | } | ||
4560 | 3594 | |||
4561 | 3595 | /** | ||
4562 | 3596 | * decode a string that is encoded w/ "chunked" transfer encoding | ||
4563 | 3597 | * as defined in rfc2068 par. 19.4.6 | ||
4564 | 3598 | * code shamelessly stolen from nusoap library by Dietrich Ayala | ||
4565 | 3599 | * | ||
4566 | 3600 | * @param string $buffer the string to be decoded | ||
4567 | 3601 | * @return string | ||
4568 | 3602 | */ | ||
4569 | 3603 | function decode_chunked($buffer) | ||
4570 | 3604 | { | ||
4571 | 3605 | // length := 0 | ||
4572 | 3606 | $length = 0; | ||
4573 | 3607 | $new = ''; | ||
4574 | 3608 | |||
4575 | 3609 | // read chunk-size, chunk-extension (if any) and crlf | ||
4576 | 3610 | // get the position of the linebreak | ||
4577 | 3611 | $chunkend = strpos($buffer,"\r\n") + 2; | ||
4578 | 3612 | $temp = substr($buffer,0,$chunkend); | ||
4579 | 3613 | $chunk_size = hexdec( trim($temp) ); | ||
4580 | 3614 | $chunkstart = $chunkend; | ||
4581 | 3615 | while($chunk_size > 0) | ||
4582 | 3616 | { | ||
4583 | 3617 | $chunkend = strpos($buffer, "\r\n", $chunkstart + $chunk_size); | ||
4584 | 3618 | |||
4585 | 3619 | // just in case we got a broken connection | ||
4586 | 3620 | if($chunkend == false) | ||
4587 | 3621 | { | ||
4588 | 3622 | $chunk = substr($buffer,$chunkstart); | ||
4589 | 3623 | // append chunk-data to entity-body | ||
4590 | 3624 | $new .= $chunk; | ||
4591 | 3625 | $length += strlen($chunk); | ||
4592 | 3626 | break; | ||
4593 | 3627 | } | ||
4594 | 3628 | |||
4595 | 3629 | // read chunk-data and crlf | ||
4596 | 3630 | $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); | ||
4597 | 3631 | // append chunk-data to entity-body | ||
4598 | 3632 | $new .= $chunk; | ||
4599 | 3633 | // length := length + chunk-size | ||
4600 | 3634 | $length += strlen($chunk); | ||
4601 | 3635 | // read chunk-size and crlf | ||
4602 | 3636 | $chunkstart = $chunkend + 2; | ||
4603 | 3637 | |||
4604 | 3638 | $chunkend = strpos($buffer,"\r\n",$chunkstart)+2; | ||
4605 | 3639 | if($chunkend == false) | ||
4606 | 3640 | { | ||
4607 | 3641 | break; //just in case we got a broken connection | ||
4608 | 3642 | } | ||
4609 | 3643 | $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); | ||
4610 | 3644 | $chunk_size = hexdec( trim($temp) ); | ||
4611 | 3645 | $chunkstart = $chunkend; | ||
4612 | 3646 | } | ||
4613 | 3647 | return $new; | ||
4614 | 3648 | } | ||
4615 | 3649 | |||
4616 | 3650 | /** | ||
4617 | 3651 | * xml charset encoding guessing helper function. | ||
4618 | 3652 | * Tries to determine the charset encoding of an XML chunk received over HTTP. | ||
4619 | 3653 | * NB: according to the spec (RFC 3023), if text/xml content-type is received over HTTP without a content-type, | ||
4620 | 3654 | * we SHOULD assume it is strictly US-ASCII. But we try to be more tolerant of unconforming (legacy?) clients/servers, | ||
4621 | 3655 | * which will be most probably using UTF-8 anyway... | ||
4622 | 3656 | * | ||
4623 | 3657 | * @param string $httpheaders the http Content-type header | ||
4624 | 3658 | * @param string $xmlchunk xml content buffer | ||
4625 | 3659 | * @param string $encoding_prefs comma separated list of character encodings to be used as default (when mb extension is enabled) | ||
4626 | 3660 | * | ||
4627 | 3661 | * @todo explore usage of mb_http_input(): does it detect http headers + post data? if so, use it instead of hand-detection!!! | ||
4628 | 3662 | */ | ||
4629 | 3663 | function guess_encoding($httpheader='', $xmlchunk='', $encoding_prefs=null) | ||
4630 | 3664 | { | ||
4631 | 3665 | // discussion: see http://www.yale.edu/pclt/encoding/ | ||
4632 | 3666 | // 1 - test if encoding is specified in HTTP HEADERS | ||
4633 | 3667 | |||
4634 | 3668 | //Details: | ||
4635 | 3669 | // LWS: (\13\10)?( |\t)+ | ||
4636 | 3670 | // token: (any char but excluded stuff)+ | ||
4637 | 3671 | // quoted string: " (any char but double quotes and cointrol chars)* " | ||
4638 | 3672 | // header: Content-type = ...; charset=value(; ...)* | ||
4639 | 3673 | // where value is of type token, no LWS allowed between 'charset' and value | ||
4640 | 3674 | // Note: we do not check for invalid chars in VALUE: | ||
4641 | 3675 | // this had better be done using pure ereg as below | ||
4642 | 3676 | // Note 2: we might be removing whitespace/tabs that ought to be left in if | ||
4643 | 3677 | // the received charset is a quoted string. But nobody uses such charset names... | ||
4644 | 3678 | |||
4645 | 3679 | /// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it? | ||
4646 | 3680 | $matches = array(); | ||
4647 | 3681 | if(preg_match('/;\s*charset\s*=([^;]+)/i', $httpheader, $matches)) | ||
4648 | 3682 | { | ||
4649 | 3683 | return strtoupper(trim($matches[1], " \t\"")); | ||
4650 | 3684 | } | ||
4651 | 3685 | |||
4652 | 3686 | // 2 - scan the first bytes of the data for a UTF-16 (or other) BOM pattern | ||
4653 | 3687 | // (source: http://www.w3.org/TR/2000/REC-xml-20001006) | ||
4654 | 3688 | // NOTE: actually, according to the spec, even if we find the BOM and determine | ||
4655 | 3689 | // an encoding, we should check if there is an encoding specified | ||
4656 | 3690 | // in the xml declaration, and verify if they match. | ||
4657 | 3691 | /// @todo implement check as described above? | ||
4658 | 3692 | /// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM) | ||
4659 | 3693 | if(preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlchunk)) | ||
4660 | 3694 | { | ||
4661 | 3695 | return 'UCS-4'; | ||
4662 | 3696 | } | ||
4663 | 3697 | elseif(preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlchunk)) | ||
4664 | 3698 | { | ||
4665 | 3699 | return 'UTF-16'; | ||
4666 | 3700 | } | ||
4667 | 3701 | elseif(preg_match('/^(\xEF\xBB\xBF)/', $xmlchunk)) | ||
4668 | 3702 | { | ||
4669 | 3703 | return 'UTF-8'; | ||
4670 | 3704 | } | ||
4671 | 3705 | |||
4672 | 3706 | // 3 - test if encoding is specified in the xml declaration | ||
4673 | 3707 | // Details: | ||
4674 | 3708 | // SPACE: (#x20 | #x9 | #xD | #xA)+ === [ \x9\xD\xA]+ | ||
4675 | 3709 | // EQ: SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]* | ||
4676 | 3710 | if (preg_match('/^<\?xml\s+version\s*=\s*'. "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))". | ||
4677 | 3711 | '\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/", | ||
4678 | 3712 | $xmlchunk, $matches)) | ||
4679 | 3713 | { | ||
4680 | 3714 | return strtoupper(substr($matches[2], 1, -1)); | ||
4681 | 3715 | } | ||
4682 | 3716 | |||
4683 | 3717 | // 4 - if mbstring is available, let it do the guesswork | ||
4684 | 3718 | // NB: we favour finding an encoding that is compatible with what we can process | ||
4685 | 3719 | if(extension_loaded('mbstring')) | ||
4686 | 3720 | { | ||
4687 | 3721 | if($encoding_prefs) | ||
4688 | 3722 | { | ||
4689 | 3723 | $enc = mb_detect_encoding($xmlchunk, $encoding_prefs); | ||
4690 | 3724 | } | ||
4691 | 3725 | else | ||
4692 | 3726 | { | ||
4693 | 3727 | $enc = mb_detect_encoding($xmlchunk); | ||
4694 | 3728 | } | ||
4695 | 3729 | // NB: mb_detect likes to call it ascii, xml parser likes to call it US_ASCII... | ||
4696 | 3730 | // IANA also likes better US-ASCII, so go with it | ||
4697 | 3731 | if($enc == 'ASCII') | ||
4698 | 3732 | { | ||
4699 | 3733 | $enc = 'US-'.$enc; | ||
4700 | 3734 | } | ||
4701 | 3735 | return $enc; | ||
4702 | 3736 | } | ||
4703 | 3737 | else | ||
4704 | 3738 | { | ||
4705 | 3739 | // no encoding specified: as per HTTP1.1 assume it is iso-8859-1? | ||
4706 | 3740 | // Both RFC 2616 (HTTP 1.1) and 1945 (HTTP 1.0) clearly state that for text/xxx content types | ||
4707 | 3741 | // this should be the standard. And we should be getting text/xml as request and response. | ||
4708 | 3742 | // BUT we have to be backward compatible with the lib, which always used UTF-8 as default... | ||
4709 | 3743 | return $GLOBALS['xmlrpc_defencoding']; | ||
4710 | 3744 | } | ||
4711 | 3745 | } | ||
4712 | 3746 | |||
4713 | 3747 | /** | ||
4714 | 3748 | * Checks if a given charset encoding is present in a list of encodings or | ||
4715 | 3749 | * if it is a valid subset of any encoding in the list | ||
4716 | 3750 | * @param string $encoding charset to be tested | ||
4717 | 3751 | * @param mixed $validlist comma separated list of valid charsets (or array of charsets) | ||
4718 | 3752 | */ | ||
4719 | 3753 | function is_valid_charset($encoding, $validlist) | ||
4720 | 3754 | { | ||
4721 | 3755 | $charset_supersets = array( | ||
4722 | 3756 | 'US-ASCII' => array ('ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', | ||
4723 | 3757 | 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', | ||
4724 | 3758 | 'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-12', | ||
4725 | 3759 | 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'UTF-8', | ||
4726 | 3760 | 'EUC-JP', 'EUC-', 'EUC-KR', 'EUC-CN') | ||
4727 | 3761 | ); | ||
4728 | 3762 | if (is_string($validlist)) | ||
4729 | 3763 | $validlist = explode(',', $validlist); | ||
4730 | 3764 | if (@in_array(strtoupper($encoding), $validlist)) | ||
4731 | 3765 | return true; | ||
4732 | 3766 | else | ||
4733 | 3767 | { | ||
4734 | 3768 | if (array_key_exists($encoding, $charset_supersets)) | ||
4735 | 3769 | foreach ($validlist as $allowed) | ||
4736 | 3770 | if (in_array($allowed, $charset_supersets[$encoding])) | ||
4737 | 3771 | return true; | ||
4738 | 3772 | return false; | ||
4739 | 3773 | } | ||
4740 | 3774 | } | ||
4741 | 3775 | |||
4742 | 3776 | ?> | ||
4743 | 0 | \ No newline at end of file | 3777 | \ No newline at end of file |
4744 | 1 | 3778 | ||
4745 | === added file 'Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc_wrappers.inc' | |||
4746 | --- Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc_wrappers.inc 1970-01-01 00:00:00 +0000 | |||
4747 | +++ Savoirfairelinux_Claim/app/code/local/Savoirfairelinux/Claim/lib/xmlrpc_wrappers.inc 2012-08-10 13:37:19 +0000 | |||
4748 | @@ -0,0 +1,955 @@ | |||
4749 | 1 | <?php | ||
4750 | 2 | /** | ||
4751 | 3 | * PHP-XMLRPC "wrapper" functions | ||
4752 | 4 | * Generate stubs to transparently access xmlrpc methods as php functions and viceversa | ||
4753 | 5 | * | ||
4754 | 6 | * @version $Id: xmlrpc_wrappers.inc,v 1.13 2008/09/20 01:23:47 ggiunta Exp $ | ||
4755 | 7 | * @author Gaetano Giunta | ||
4756 | 8 | * @copyright (C) 2006-2009 G. Giunta | ||
4757 | 9 | * @license code licensed under the BSD License: http://phpxmlrpc.sourceforge.net/license.txt | ||
4758 | 10 | * | ||
4759 | 11 | * @todo separate introspection from code generation for func-2-method wrapping | ||
4760 | 12 | * @todo use some better templating system for code generation? | ||
4761 | 13 | * @todo implement method wrapping with preservation of php objs in calls | ||
4762 | 14 | * @todo when wrapping methods without obj rebuilding, use return_type = 'phpvals' (faster) | ||
4763 | 15 | * @todo implement self-parsing of php code for PHP <= 4 | ||
4764 | 16 | */ | ||
4765 | 17 | |||
4766 | 18 | // requires: xmlrpc.inc | ||
4767 | 19 | |||
4768 | 20 | /** | ||
4769 | 21 | * Given a string defining a php type or phpxmlrpc type (loosely defined: strings | ||
4770 | 22 | * accepted come from javadoc blocks), return corresponding phpxmlrpc type. | ||
4771 | 23 | * NB: for php 'resource' types returns empty string, since resources cannot be serialized; | ||
4772 | 24 | * for php class names returns 'struct', since php objects can be serialized as xmlrpc structs | ||
4773 | 25 | * for php arrays always return array, even though arrays sometiles serialize as json structs | ||
4774 | 26 | * @param string $phptype | ||
4775 | 27 | * @return string | ||
4776 | 28 | */ | ||
4777 | 29 | function php_2_xmlrpc_type($phptype) | ||
4778 | 30 | { | ||
4779 | 31 | switch(strtolower($phptype)) | ||
4780 | 32 | { | ||
4781 | 33 | case 'string': | ||
4782 | 34 | return $GLOBALS['xmlrpcString']; | ||
4783 | 35 | case 'integer': | ||
4784 | 36 | case $GLOBALS['xmlrpcInt']: // 'int' | ||
4785 | 37 | case $GLOBALS['xmlrpcI4']: | ||
4786 | 38 | return $GLOBALS['xmlrpcInt']; | ||
4787 | 39 | case 'double': | ||
4788 | 40 | return $GLOBALS['xmlrpcDouble']; | ||
4789 | 41 | case 'boolean': | ||
4790 | 42 | return $GLOBALS['xmlrpcBoolean']; | ||
4791 | 43 | case 'array': | ||
4792 | 44 | return $GLOBALS['xmlrpcArray']; | ||
4793 | 45 | case 'object': | ||
4794 | 46 | return $GLOBALS['xmlrpcStruct']; | ||
4795 | 47 | case $GLOBALS['xmlrpcBase64']: | ||
4796 | 48 | case $GLOBALS['xmlrpcStruct']: | ||
4797 | 49 | return strtolower($phptype); | ||
4798 | 50 | case 'resource': | ||
4799 | 51 | return ''; | ||
4800 | 52 | default: | ||
4801 | 53 | if(class_exists($phptype)) | ||
4802 | 54 | { | ||
4803 | 55 | return $GLOBALS['xmlrpcStruct']; | ||
4804 | 56 | } | ||
4805 | 57 | else | ||
4806 | 58 | { | ||
4807 | 59 | // unknown: might be any 'extended' xmlrpc type | ||
4808 | 60 | return $GLOBALS['xmlrpcValue']; | ||
4809 | 61 | } | ||
4810 | 62 | } | ||
4811 | 63 | } | ||
4812 | 64 | |||
4813 | 65 | /** | ||
4814 | 66 | * Given a string defining a phpxmlrpc type return corresponding php type. | ||
4815 | 67 | * @param string $xmlrpctype | ||
4816 | 68 | * @return string | ||
4817 | 69 | */ | ||
4818 | 70 | function xmlrpc_2_php_type($xmlrpctype) | ||
4819 | 71 | { | ||
4820 | 72 | switch(strtolower($xmlrpctype)) | ||
4821 | 73 | { | ||
4822 | 74 | case 'base64': | ||
4823 | 75 | case 'datetime.iso8601': | ||
4824 | 76 | case 'string': | ||
4825 | 77 | return $GLOBALS['xmlrpcString']; | ||
4826 | 78 | case 'int': | ||
4827 | 79 | case 'i4': | ||
4828 | 80 | return 'integer'; | ||
4829 | 81 | case 'struct': | ||
4830 | 82 | case 'array': | ||
4831 | 83 | return 'array'; | ||
4832 | 84 | case 'double': | ||
4833 | 85 | return 'float'; | ||
4834 | 86 | case 'undefined': | ||
4835 | 87 | return 'mixed'; | ||
4836 | 88 | case 'boolean': | ||
4837 | 89 | case 'null': | ||
4838 | 90 | default: | ||
4839 | 91 | // unknown: might be any xmlrpc type | ||
4840 | 92 | return strtolower($xmlrpctype); | ||
4841 | 93 | } | ||
4842 | 94 | } | ||
4843 | 95 | |||
4844 | 96 | /** | ||
4845 | 97 | * Given a user-defined PHP function, create a PHP 'wrapper' function that can | ||
4846 | 98 | * be exposed as xmlrpc method from an xmlrpc_server object and called from remote | ||
4847 | 99 | * clients (as well as its corresponding signature info). | ||
4848 | 100 | * | ||
4849 | 101 | * Since php is a typeless language, to infer types of input and output parameters, | ||
4850 | 102 | * it relies on parsing the javadoc-style comment block associated with the given | ||
4851 | 103 | * function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and base64) | ||
4852 | 104 | * in the @param tag is also allowed, if you need the php function to receive/send | ||
4853 | 105 | * data in that particular format (note that base64 encoding/decoding is transparently | ||
4854 | 106 | * carried out by the lib, while datetime vals are passed around as strings) | ||
4855 | 107 | * | ||
4856 | 108 | * Known limitations: | ||
4857 | 109 | * - requires PHP 5.0.3 + | ||
4858 | 110 | * - only works for user-defined functions, not for PHP internal functions | ||
4859 | 111 | * (reflection does not support retrieving number/type of params for those) | ||
4860 | 112 | * - functions returning php objects will generate special xmlrpc responses: | ||
4861 | 113 | * when the xmlrpc decoding of those responses is carried out by this same lib, using | ||
4862 | 114 | * the appropriate param in php_xmlrpc_decode, the php objects will be rebuilt. | ||
4863 | 115 | * In short: php objects can be serialized, too (except for their resource members), | ||
4864 | 116 | * using this function. | ||
4865 | 117 | * Other libs might choke on the very same xml that will be generated in this case | ||
4866 | 118 | * (i.e. it has a nonstandard attribute on struct element tags) | ||
4867 | 119 | * - usage of javadoc @param tags using param names in a different order from the | ||
4868 | 120 | * function prototype is not considered valid (to be fixed?) | ||
4869 | 121 | * | ||
4870 | 122 | * Note that since rel. 2.0RC3 the preferred method to have the server call 'standard' | ||
4871 | 123 | * php functions (ie. functions not expecting a single xmlrpcmsg obj as parameter) | ||
4872 | 124 | * is by making use of the functions_parameters_type class member. | ||
4873 | 125 | * | ||
4874 | 126 | * @param string $funcname the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') and array('class', 'methodname') are ok too | ||
4875 | 127 | * @param string $newfuncname (optional) name for function to be created | ||
4876 | 128 | * @param array $extra_options (optional) array of options for conversion. valid values include: | ||
4877 | 129 | * bool return_source when true, php code w. function definition will be returned, not evaluated | ||
4878 | 130 | * bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects | ||
4879 | 131 | * bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers --- | ||
4880 | 132 | * bool suppress_warnings remove from produced xml any runtime warnings due to the php function being invoked | ||
4881 | 133 | * @return false on error, or an array containing the name of the new php function, | ||
4882 | 134 | * its signature and docs, to be used in the server dispatch map | ||
4883 | 135 | * | ||
4884 | 136 | * @todo decide how to deal with params passed by ref: bomb out or allow? | ||
4885 | 137 | * @todo finish using javadoc info to build method sig if all params are named but out of order | ||
4886 | 138 | * @todo add a check for params of 'resource' type | ||
4887 | 139 | * @todo add some trigger_errors / error_log when returning false? | ||
4888 | 140 | * @todo what to do when the PHP function returns NULL? we are currently returning an empty string value... | ||
4889 | 141 | * @todo add an option to suppress php warnings in invocation of user function, similar to server debug level 3? | ||
4890 | 142 | * @todo if $newfuncname is empty, we could use create_user_func instead of eval, as it is possibly faster | ||
4891 | 143 | * @todo add a verbatim_object_copy parameter to allow avoiding the same obj instance? | ||
4892 | 144 | */ | ||
4893 | 145 | function wrap_php_function($funcname, $newfuncname='', $extra_options=array()) | ||
4894 | 146 | { | ||
4895 | 147 | $buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true; | ||
4896 | 148 | $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; | ||
4897 | 149 | $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false; | ||
4898 | 150 | $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false; | ||
4899 | 151 | $catch_warnings = isset($extra_options['suppress_warnings']) && $extra_options['suppress_warnings'] ? '@' : ''; | ||
4900 | 152 | |||
4901 | 153 | if(version_compare(phpversion(), '5.0.3') == -1) | ||
4902 | 154 | { | ||
4903 | 155 | // up to php 5.0.3 some useful reflection methods were missing | ||
4904 | 156 | error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3'); | ||
4905 | 157 | return false; | ||
4906 | 158 | } | ||
4907 | 159 | |||
4908 | 160 | $exists = false; | ||
4909 | 161 | if (is_string($funcname) && strpos($funcname, '::') !== false) | ||
4910 | 162 | { | ||
4911 | 163 | $funcname = explode('::', $funcname); | ||
4912 | 164 | } | ||
4913 | 165 | if(is_array($funcname)) | ||
4914 | 166 | { | ||
4915 | 167 | if(count($funcname) < 2 || (!is_string($funcname[0]) && !is_object($funcname[0]))) | ||
4916 | 168 | { | ||
4917 | 169 | error_log('XML-RPC: syntax for function to be wrapped is wrong'); | ||
4918 | 170 | return false; | ||
4919 | 171 | } | ||
4920 | 172 | if(is_string($funcname[0])) | ||
4921 | 173 | { | ||
4922 | 174 | $plainfuncname = implode('::', $funcname); | ||
4923 | 175 | } | ||
4924 | 176 | elseif(is_object($funcname[0])) | ||
4925 | 177 | { | ||
4926 | 178 | $plainfuncname = get_class($funcname[0]) . '->' . $funcname[1]; | ||
4927 | 179 | } | ||
4928 | 180 | $exists = method_exists($funcname[0], $funcname[1]); | ||
4929 | 181 | if (!$exists && version_compare(phpversion(), '5.1') < 0) | ||
4930 | 182 | { | ||
4931 | 183 | // workaround for php 5.0: static class methods are not seen by method_exists | ||
4932 | 184 | $exists = is_callable( $funcname ); | ||
4933 | 185 | } | ||
4934 | 186 | } | ||
4935 | 187 | else | ||
4936 | 188 | { | ||
4937 | 189 | $plainfuncname = $funcname; | ||
4938 | 190 | $exists = function_exists($funcname); | ||
4939 | 191 | } | ||
4940 | 192 | |||
4941 | 193 | if(!$exists) | ||
4942 | 194 | { | ||
4943 | 195 | error_log('XML-RPC: function to be wrapped is not defined: '.$plainfuncname); | ||
4944 | 196 | return false; | ||
4945 | 197 | } | ||
4946 | 198 | else | ||
4947 | 199 | { | ||
4948 | 200 | // determine name of new php function | ||
4949 | 201 | if($newfuncname == '') | ||
4950 | 202 | { | ||
4951 | 203 | if(is_array($funcname)) | ||
4952 | 204 | { | ||
4953 | 205 | if(is_string($funcname[0])) | ||
4954 | 206 | $xmlrpcfuncname = "{$prefix}_".implode('_', $funcname); | ||
4955 | 207 | else | ||
4956 | 208 | $xmlrpcfuncname = "{$prefix}_".get_class($funcname[0]) . '_' . $funcname[1]; | ||
4957 | 209 | } | ||
4958 | 210 | else | ||
4959 | 211 | { | ||
4960 | 212 | $xmlrpcfuncname = "{$prefix}_$funcname"; | ||
4961 | 213 | } | ||
4962 | 214 | } | ||
4963 | 215 | else | ||
4964 | 216 | { | ||
4965 | 217 | $xmlrpcfuncname = $newfuncname; | ||
4966 | 218 | } | ||
4967 | 219 | while($buildit && function_exists($xmlrpcfuncname)) | ||
4968 | 220 | { | ||
4969 | 221 | $xmlrpcfuncname .= 'x'; | ||
4970 | 222 | } | ||
4971 | 223 | |||
4972 | 224 | // start to introspect PHP code | ||
4973 | 225 | if(is_array($funcname)) | ||
4974 | 226 | { | ||
4975 | 227 | $func = new ReflectionMethod($funcname[0], $funcname[1]); | ||
4976 | 228 | if($func->isPrivate()) | ||
4977 | 229 | { | ||
4978 | 230 | error_log('XML-RPC: method to be wrapped is private: '.$plainfuncname); | ||
4979 | 231 | return false; | ||
4980 | 232 | } | ||
4981 | 233 | if($func->isProtected()) | ||
4982 | 234 | { | ||
4983 | 235 | error_log('XML-RPC: method to be wrapped is protected: '.$plainfuncname); | ||
4984 | 236 | return false; | ||
4985 | 237 | } | ||
4986 | 238 | if($func->isConstructor()) | ||
4987 | 239 | { | ||
4988 | 240 | error_log('XML-RPC: method to be wrapped is the constructor: '.$plainfuncname); | ||
4989 | 241 | return false; | ||
4990 | 242 | } | ||
4991 | 243 | // php 503 always says isdestructor = true... | ||
4992 | 244 | if( version_compare(phpversion(), '5.0.3') != 0 && $func->isDestructor()) | ||
4993 | 245 | { | ||
4994 | 246 | error_log('XML-RPC: method to be wrapped is the destructor: '.$plainfuncname); | ||
4995 | 247 | return false; | ||
4996 | 248 | } | ||
4997 | 249 | if($func->isAbstract()) | ||
4998 | 250 | { | ||
4999 | 251 | error_log('XML-RPC: method to be wrapped is abstract: '.$plainfuncname); | ||
5000 | 252 | return false; |
The diff has been truncated for viewing.