1<?php 2/* 3 4NuSOAP - Web Services Toolkit for PHP 5 6Copyright (c) 2002 NuSphere Corporation 7 8This library is free software; you can redistribute it and/or 9modify it under the terms of the GNU Lesser General Public 10License as published by the Free Software Foundation; either 11version 2.1 of the License, or (at your option) any later version. 12 13This library is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16Lesser General Public License for more details. 17 18You should have received a copy of the GNU Lesser General Public 19along with this program. If not, see <https://www.gnu.org/licenses/>. 20 21The NuSOAP project home is: 22http://sourceforge.net/projects/nusoap/ 23 24The primary support for NuSOAP is the mailing list: 25nusoap-general@lists.sourceforge.net 26 27If you have any questions or comments, please email: 28 29Dietrich Ayala 30dietrich@ganx4.com 31http://dietrich.ganx4.com/nusoap 32 33NuSphere Corporation 34http://www.nusphere.com 35 36*/ 37 38/*require_once('nusoap.php');*/ 39/* PEAR Mail_MIME library */ 40require_once('Mail/mimeDecode.php'); 41require_once('Mail/mimePart.php'); 42 43/** 44* nusoap_client_mime client supporting MIME attachments defined at 45* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. 46* 47* @author Scott Nichol <snichol@users.sourceforge.net> 48* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list 49* @access public 50*/ 51class nusoap_client_mime extends nusoap_client { 52 /** 53 * @var array Each array element in the return is an associative array with keys 54 * data, filename, contenttype, cid 55 * @access private 56 */ 57 var $requestAttachments = array(); 58 /** 59 * @var array Each array element in the return is an associative array with keys 60 * data, filename, contenttype, cid 61 * @access private 62 */ 63 var $responseAttachments; 64 /** 65 * @var string 66 * @access private 67 */ 68 var $mimeContentType; 69 70 /** 71 * adds a MIME attachment to the current request. 72 * 73 * If the $data parameter contains an empty string, this method will read 74 * the contents of the file named by the $filename parameter. 75 * 76 * If the $cid parameter is false, this method will generate the cid. 77 * 78 * @param string $data The data of the attachment 79 * @param string $filename The filename of the attachment (default is empty string) 80 * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) 81 * @param string $cid The content-id (cid) of the attachment (default is false) 82 * @return string The content-id (cid) of the attachment 83 * @access public 84 */ 85 function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { 86 if (! $cid) { 87 $cid = md5(uniqid(time())); 88 } 89 90 $info['data'] = $data; 91 $info['filename'] = $filename; 92 $info['contenttype'] = $contenttype; 93 $info['cid'] = $cid; 94 95 $this->requestAttachments[] = $info; 96 97 return $cid; 98 } 99 100 /** 101 * clears the MIME attachments for the current request. 102 * 103 * @access public 104 */ 105 function clearAttachments() { 106 $this->requestAttachments = array(); 107 } 108 109 /** 110 * gets the MIME attachments from the current response. 111 * 112 * Each array element in the return is an associative array with keys 113 * data, filename, contenttype, cid. These keys correspond to the parameters 114 * for addAttachment. 115 * 116 * @return array The attachments. 117 * @access public 118 */ 119 function getAttachments() { 120 return $this->responseAttachments; 121 } 122 123 /** 124 * gets the HTTP body for the current request. 125 * 126 * @param string $soapmsg The SOAP payload 127 * @return string The HTTP body, which includes the SOAP payload 128 * @access private 129 */ 130 function getHTTPBody($soapmsg) { 131 if (count($this->requestAttachments) > 0) { 132 $params['content_type'] = 'multipart/related; type="text/xml"'; 133 $mimeMessage = new Mail_mimePart('', $params); 134 unset($params); 135 136 $params['content_type'] = 'text/xml'; 137 $params['encoding'] = '8bit'; 138 $params['charset'] = $this->soap_defencoding; 139 $mimeMessage->addSubpart($soapmsg, $params); 140 141 foreach ($this->requestAttachments as $att) { 142 unset($params); 143 144 $params['content_type'] = $att['contenttype']; 145 $params['encoding'] = 'base64'; 146 $params['disposition'] = 'attachment'; 147 $params['dfilename'] = $att['filename']; 148 $params['cid'] = $att['cid']; 149 150 if ($att['data'] == '' && $att['filename'] <> '') { 151 if ($fd = fopen($att['filename'], 'rb')) { 152 $data = fread($fd, filesize($att['filename'])); 153 fclose($fd); 154 } else { 155 $data = ''; 156 } 157 $mimeMessage->addSubpart($data, $params); 158 } else { 159 $mimeMessage->addSubpart($att['data'], $params); 160 } 161 } 162 163 $output = $mimeMessage->encode(); 164 $mimeHeaders = $output['headers']; 165 166 foreach ($mimeHeaders as $k => $v) { 167 $this->debug("MIME header $k: $v"); 168 if (strtolower($k) == 'content-type') { 169 // PHP header() seems to strip leading whitespace starting 170 // the second line, so force everything to one line 171 $this->mimeContentType = str_replace("\r\n", " ", $v); 172 } 173 } 174 175 return $output['body']; 176 } 177 178 return parent::getHTTPBody($soapmsg); 179 } 180 181 /** 182 * gets the HTTP content type for the current request. 183 * 184 * Note: getHTTPBody must be called before this. 185 * 186 * @return string the HTTP content type for the current request. 187 * @access private 188 */ 189 function getHTTPContentType() { 190 if (count($this->requestAttachments) > 0) { 191 return $this->mimeContentType; 192 } 193 return parent::getHTTPContentType(); 194 } 195 196 /** 197 * gets the HTTP content type charset for the current request. 198 * returns false for non-text content types. 199 * 200 * Note: getHTTPBody must be called before this. 201 * 202 * @return string the HTTP content type charset for the current request. 203 * @access private 204 */ 205 function getHTTPContentTypeCharset() { 206 if (count($this->requestAttachments) > 0) { 207 return false; 208 } 209 return parent::getHTTPContentTypeCharset(); 210 } 211 212 /** 213 * processes SOAP message returned from server 214 * 215 * @param array $headers The HTTP headers 216 * @param string $data unprocessed response data from server 217 * @return mixed value of the message, decoded into a PHP type 218 * @access private 219 */ 220 function parseResponse($headers, $data) { 221 $this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); 222 $this->responseAttachments = array(); 223 if (strstr($headers['content-type'], 'multipart/related')) { 224 $this->debug('Decode multipart/related'); 225 $input = ''; 226 foreach ($headers as $k => $v) { 227 $input .= "$k: $v\r\n"; 228 } 229 $params['input'] = $input . "\r\n" . $data; 230 $params['include_bodies'] = true; 231 $params['decode_bodies'] = true; 232 $params['decode_headers'] = true; 233 234 $structure = Mail_mimeDecode::decode($params); 235 236 foreach ($structure->parts as $part) { 237 if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { 238 $this->debug('Have root part of type ' . $part->headers['content-type']); 239 $root = $part->body; 240 $return = parent::parseResponse($part->headers, $part->body); 241 } else { 242 $this->debug('Have an attachment of type ' . $part->headers['content-type']); 243 $info['data'] = $part->body; 244 $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; 245 $info['contenttype'] = $part->headers['content-type']; 246 $info['cid'] = $part->headers['content-id']; 247 $this->responseAttachments[] = $info; 248 } 249 } 250 251 if (isset($return)) { 252 $this->responseData = $root; 253 return $return; 254 } 255 256 $this->setError('No root part found in multipart/related content'); 257 return ''; 258 } 259 $this->debug('Not multipart/related'); 260 return parent::parseResponse($headers, $data); 261 } 262} 263 264/* 265 * For backwards compatiblity, define soapclientmime unless the PHP SOAP extension is loaded. 266 */ 267if (!extension_loaded('soap')) { 268 class soapclientmime extends nusoap_client_mime { 269 } 270} 271 272/** 273* nusoap_server_mime server supporting MIME attachments defined at 274* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. 275* 276* @author Scott Nichol <snichol@users.sourceforge.net> 277* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list 278* @access public 279*/ 280class nusoap_server_mime extends nusoap_server { 281 /** 282 * @var array Each array element in the return is an associative array with keys 283 * data, filename, contenttype, cid 284 * @access private 285 */ 286 var $requestAttachments = array(); 287 /** 288 * @var array Each array element in the return is an associative array with keys 289 * data, filename, contenttype, cid 290 * @access private 291 */ 292 var $responseAttachments; 293 /** 294 * @var string 295 * @access private 296 */ 297 var $mimeContentType; 298 299 /** 300 * adds a MIME attachment to the current response. 301 * 302 * If the $data parameter contains an empty string, this method will read 303 * the contents of the file named by the $filename parameter. 304 * 305 * If the $cid parameter is false, this method will generate the cid. 306 * 307 * @param string $data The data of the attachment 308 * @param string $filename The filename of the attachment (default is empty string) 309 * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) 310 * @param string $cid The content-id (cid) of the attachment (default is false) 311 * @return string The content-id (cid) of the attachment 312 * @access public 313 */ 314 function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { 315 if (! $cid) { 316 $cid = md5(uniqid(time())); 317 } 318 319 $info['data'] = $data; 320 $info['filename'] = $filename; 321 $info['contenttype'] = $contenttype; 322 $info['cid'] = $cid; 323 324 $this->responseAttachments[] = $info; 325 326 return $cid; 327 } 328 329 /** 330 * clears the MIME attachments for the current response. 331 * 332 * @access public 333 */ 334 function clearAttachments() { 335 $this->responseAttachments = array(); 336 } 337 338 /** 339 * gets the MIME attachments from the current request. 340 * 341 * Each array element in the return is an associative array with keys 342 * data, filename, contenttype, cid. These keys correspond to the parameters 343 * for addAttachment. 344 * 345 * @return array The attachments. 346 * @access public 347 */ 348 function getAttachments() { 349 return $this->requestAttachments; 350 } 351 352 /** 353 * gets the HTTP body for the current response. 354 * 355 * @param string $soapmsg The SOAP payload 356 * @return string The HTTP body, which includes the SOAP payload 357 * @access private 358 */ 359 function getHTTPBody($soapmsg) { 360 if (count($this->responseAttachments) > 0) { 361 $params['content_type'] = 'multipart/related; type="text/xml"'; 362 $mimeMessage = new Mail_mimePart('', $params); 363 unset($params); 364 365 $params['content_type'] = 'text/xml'; 366 $params['encoding'] = '8bit'; 367 $params['charset'] = $this->soap_defencoding; 368 $mimeMessage->addSubpart($soapmsg, $params); 369 370 foreach ($this->responseAttachments as $att) { 371 unset($params); 372 373 $params['content_type'] = $att['contenttype']; 374 $params['encoding'] = 'base64'; 375 $params['disposition'] = 'attachment'; 376 $params['dfilename'] = $att['filename']; 377 $params['cid'] = $att['cid']; 378 379 if ($att['data'] == '' && $att['filename'] <> '') { 380 if ($fd = fopen($att['filename'], 'rb')) { 381 $data = fread($fd, filesize($att['filename'])); 382 fclose($fd); 383 } else { 384 $data = ''; 385 } 386 $mimeMessage->addSubpart($data, $params); 387 } else { 388 $mimeMessage->addSubpart($att['data'], $params); 389 } 390 } 391 392 $output = $mimeMessage->encode(); 393 $mimeHeaders = $output['headers']; 394 395 foreach ($mimeHeaders as $k => $v) { 396 $this->debug("MIME header $k: $v"); 397 if (strtolower($k) == 'content-type') { 398 // PHP header() seems to strip leading whitespace starting 399 // the second line, so force everything to one line 400 $this->mimeContentType = str_replace("\r\n", " ", $v); 401 } 402 } 403 404 return $output['body']; 405 } 406 407 return parent::getHTTPBody($soapmsg); 408 } 409 410 /** 411 * gets the HTTP content type for the current response. 412 * 413 * Note: getHTTPBody must be called before this. 414 * 415 * @return string the HTTP content type for the current response. 416 * @access private 417 */ 418 function getHTTPContentType() { 419 if (count($this->responseAttachments) > 0) { 420 return $this->mimeContentType; 421 } 422 return parent::getHTTPContentType(); 423 } 424 425 /** 426 * gets the HTTP content type charset for the current response. 427 * returns false for non-text content types. 428 * 429 * Note: getHTTPBody must be called before this. 430 * 431 * @return string the HTTP content type charset for the current response. 432 * @access private 433 */ 434 function getHTTPContentTypeCharset() { 435 if (count($this->responseAttachments) > 0) { 436 return false; 437 } 438 return parent::getHTTPContentTypeCharset(); 439 } 440 441 /** 442 * processes SOAP message received from client 443 * 444 * @param array $headers The HTTP headers 445 * @param string $data unprocessed request data from client 446 * @return mixed value of the message, decoded into a PHP type 447 * @access private 448 */ 449 function parseRequest($headers, $data) { 450 $this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); 451 $this->requestAttachments = array(); 452 if (strstr($headers['content-type'], 'multipart/related')) { 453 $this->debug('Decode multipart/related'); 454 $input = ''; 455 foreach ($headers as $k => $v) { 456 $input .= "$k: $v\r\n"; 457 } 458 $params['input'] = $input . "\r\n" . $data; 459 $params['include_bodies'] = true; 460 $params['decode_bodies'] = true; 461 $params['decode_headers'] = true; 462 463 $structure = Mail_mimeDecode::decode($params); 464 465 foreach ($structure->parts as $part) { 466 if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { 467 $this->debug('Have root part of type ' . $part->headers['content-type']); 468 $return = parent::parseRequest($part->headers, $part->body); 469 } else { 470 $this->debug('Have an attachment of type ' . $part->headers['content-type']); 471 $info['data'] = $part->body; 472 $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; 473 $info['contenttype'] = $part->headers['content-type']; 474 $info['cid'] = $part->headers['content-id']; 475 $this->requestAttachments[] = $info; 476 } 477 } 478 479 if (isset($return)) { 480 return $return; 481 } 482 483 $this->setError('No root part found in multipart/related content'); 484 return; 485 } 486 $this->debug('Not multipart/related'); 487 return parent::parseRequest($headers, $data); 488 } 489} 490 491/* 492 * For backwards compatiblity 493 */ 494class nusoapservermime extends nusoap_server_mime { 495} 496 497?> 498