| [ Index ] |
|
Code source de GeekLog 1.4.1 |
1 <?php 2 3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 4 5 /** 6 * Server commands for our PHP implementation of the XML-RPC protocol 7 * 8 * This is a PEAR-ified version of Useful inc's XML-RPC for PHP. 9 * It has support for HTTP transport, proxies and authentication. 10 * 11 * PHP versions 4 and 5 12 * 13 * LICENSE: License is granted to use or modify this software 14 * ("XML-RPC for PHP") for commercial or non-commercial use provided the 15 * copyright of the author is preserved in any distributed or derivative work. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESSED OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * @category Web Services 29 * @package XML_RPC 30 * @author Edd Dumbill <edd@usefulinc.com> 31 * @author Stig Bakken <stig@php.net> 32 * @author Martin Jansen <mj@php.net> 33 * @author Daniel Convissor <danielc@php.net> 34 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 35 * @version CVS: $Id: Server.php,v 1.37 2006/10/28 16:42:34 danielc Exp $ 36 * @link http://pear.php.net/package/XML_RPC 37 */ 38 39 40 /** 41 * Pull in the XML_RPC class 42 */ 43 require_once 'XML/RPC.php'; 44 45 46 /** 47 * signature for system.listMethods: return = array, 48 * parameters = a string or nothing 49 * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] 50 */ 51 $GLOBALS['XML_RPC_Server_listMethods_sig'] = array( 52 array($GLOBALS['XML_RPC_Array'], 53 $GLOBALS['XML_RPC_String'] 54 ), 55 array($GLOBALS['XML_RPC_Array']) 56 ); 57 58 /** 59 * docstring for system.listMethods 60 * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] 61 */ 62 $GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' 63 . ' methods that the XML-RPC server knows how to dispatch'; 64 65 /** 66 * signature for system.methodSignature: return = array, 67 * parameters = string 68 * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] 69 */ 70 $GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( 71 array($GLOBALS['XML_RPC_Array'], 72 $GLOBALS['XML_RPC_String'] 73 ) 74 ); 75 76 /** 77 * docstring for system.methodSignature 78 * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] 79 */ 80 $GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' 81 . ' signatures (an array of arrays) for the method name passed. If' 82 . ' no signatures are known, returns a none-array (test for type !=' 83 . ' array to detect missing signature)'; 84 85 /** 86 * signature for system.methodHelp: return = string, 87 * parameters = string 88 * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] 89 */ 90 $GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( 91 array($GLOBALS['XML_RPC_String'], 92 $GLOBALS['XML_RPC_String'] 93 ) 94 ); 95 96 /** 97 * docstring for methodHelp 98 * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] 99 */ 100 $GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' 101 . ' for the method passed, otherwise returns an empty string'; 102 103 /** 104 * dispatch map for the automatically declared XML-RPC methods. 105 * @global array $GLOBALS['XML_RPC_Server_dmap'] 106 */ 107 $GLOBALS['XML_RPC_Server_dmap'] = array( 108 'system.listMethods' => array( 109 'function' => 'XML_RPC_Server_listMethods', 110 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], 111 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] 112 ), 113 'system.methodHelp' => array( 114 'function' => 'XML_RPC_Server_methodHelp', 115 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], 116 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] 117 ), 118 'system.methodSignature' => array( 119 'function' => 'XML_RPC_Server_methodSignature', 120 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], 121 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] 122 ) 123 ); 124 125 /** 126 * @global string $GLOBALS['XML_RPC_Server_debuginfo'] 127 */ 128 $GLOBALS['XML_RPC_Server_debuginfo'] = ''; 129 130 131 /** 132 * Lists all the methods that the XML-RPC server knows how to dispatch 133 * 134 * @return object a new XML_RPC_Response object 135 */ 136 function XML_RPC_Server_listMethods($server, $m) 137 { 138 global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; 139 140 $v = new XML_RPC_Value(); 141 $outAr = array(); 142 foreach ($server->dmap as $key => $val) { 143 $outAr[] = new XML_RPC_Value($key, 'string'); 144 } 145 foreach ($XML_RPC_Server_dmap as $key => $val) { 146 $outAr[] = new XML_RPC_Value($key, 'string'); 147 } 148 $v->addArray($outAr); 149 return new XML_RPC_Response($v); 150 } 151 152 /** 153 * Returns an array of known signatures (an array of arrays) 154 * for the given method 155 * 156 * If no signatures are known, returns a none-array 157 * (test for type != array to detect missing signature) 158 * 159 * @return object a new XML_RPC_Response object 160 */ 161 function XML_RPC_Server_methodSignature($server, $m) 162 { 163 global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; 164 165 $methName = $m->getParam(0); 166 $methName = $methName->scalarval(); 167 if (strpos($methName, 'system.') === 0) { 168 $dmap = $XML_RPC_Server_dmap; 169 $sysCall = 1; 170 } else { 171 $dmap = $server->dmap; 172 $sysCall = 0; 173 } 174 // print "<!-- ${methName} -->\n"; 175 if (isset($dmap[$methName])) { 176 if ($dmap[$methName]['signature']) { 177 $sigs = array(); 178 $thesigs = $dmap[$methName]['signature']; 179 for ($i = 0; $i < sizeof($thesigs); $i++) { 180 $cursig = array(); 181 $inSig = $thesigs[$i]; 182 for ($j = 0; $j < sizeof($inSig); $j++) { 183 $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); 184 } 185 $sigs[] = new XML_RPC_Value($cursig, 'array'); 186 } 187 $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); 188 } else { 189 $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); 190 } 191 } else { 192 $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], 193 $XML_RPC_str['introspect_unknown']); 194 } 195 return $r; 196 } 197 198 /** 199 * Returns help text if defined for the method passed, otherwise returns 200 * an empty string 201 * 202 * @return object a new XML_RPC_Response object 203 */ 204 function XML_RPC_Server_methodHelp($server, $m) 205 { 206 global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; 207 208 $methName = $m->getParam(0); 209 $methName = $methName->scalarval(); 210 if (strpos($methName, 'system.') === 0) { 211 $dmap = $XML_RPC_Server_dmap; 212 $sysCall = 1; 213 } else { 214 $dmap = $server->dmap; 215 $sysCall = 0; 216 } 217 218 if (isset($dmap[$methName])) { 219 if ($dmap[$methName]['docstring']) { 220 $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), 221 'string'); 222 } else { 223 $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); 224 } 225 } else { 226 $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], 227 $XML_RPC_str['introspect_unknown']); 228 } 229 return $r; 230 } 231 232 /** 233 * @return void 234 */ 235 function XML_RPC_Server_debugmsg($m) 236 { 237 global $XML_RPC_Server_debuginfo; 238 $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; 239 } 240 241 242 /** 243 * A server for receiving and replying to XML RPC requests 244 * 245 * <code> 246 * $server = new XML_RPC_Server( 247 * array( 248 * 'isan8' => 249 * array( 250 * 'function' => 'is_8', 251 * 'signature' => 252 * array( 253 * array('boolean', 'int'), 254 * array('boolean', 'int', 'boolean'), 255 * array('boolean', 'string'), 256 * array('boolean', 'string', 'boolean'), 257 * ), 258 * 'docstring' => 'Is the value an 8?' 259 * ), 260 * ), 261 * 1, 262 * 0 263 * ); 264 * </code> 265 * 266 * @category Web Services 267 * @package XML_RPC 268 * @author Edd Dumbill <edd@usefulinc.com> 269 * @author Stig Bakken <stig@php.net> 270 * @author Martin Jansen <mj@php.net> 271 * @author Daniel Convissor <danielc@php.net> 272 * @copyright 1999-2001 Edd Dumbill, 2001-2006 The PHP Group 273 * @version Release: 1.5.1 274 * @link http://pear.php.net/package/XML_RPC 275 */ 276 class XML_RPC_Server 277 { 278 /** 279 * Should the payload's content be passed through mb_convert_encoding()? 280 * 281 * @see XML_RPC_Server::setConvertPayloadEncoding() 282 * @since Property available since Release 1.5.1 283 * @var boolean 284 */ 285 var $convert_payload_encoding = false; 286 287 /** 288 * The dispatch map, listing the methods this server provides. 289 * @var array 290 */ 291 var $dmap = array(); 292 293 /** 294 * The present response's encoding 295 * @var string 296 * @see XML_RPC_Message::getEncoding() 297 */ 298 var $encoding = ''; 299 300 /** 301 * Debug mode (0 = off, 1 = on) 302 * @var integer 303 */ 304 var $debug = 0; 305 306 /** 307 * The response's HTTP headers 308 * @var string 309 */ 310 var $server_headers = ''; 311 312 /** 313 * The response's XML payload 314 * @var string 315 */ 316 var $server_payload = ''; 317 318 319 /** 320 * Constructor for the XML_RPC_Server class 321 * 322 * @param array $dispMap the dispatch map. An associative array 323 * explaining each function. The keys of the main 324 * array are the procedure names used by the 325 * clients. The value is another associative array 326 * that contains up to three elements: 327 * + The 'function' element's value is the name 328 * of the function or method that gets called. 329 * To define a class' method: 'class::method'. 330 * + The 'signature' element (optional) is an 331 * array describing the return values and 332 * parameters 333 * + The 'docstring' element (optional) is a 334 * string describing what the method does 335 * @param int $serviceNow should the HTTP response be sent now? 336 * (1 = yes, 0 = no) 337 * @param int $debug should debug output be displayed? 338 * (1 = yes, 0 = no) 339 * 340 * @return void 341 */ 342 function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) 343 { 344 global $HTTP_RAW_POST_DATA; 345 346 if ($debug) { 347 $this->debug = 1; 348 } else { 349 $this->debug = 0; 350 } 351 352 $this->dmap = $dispMap; 353 354 if ($serviceNow) { 355 $this->service(); 356 } else { 357 $this->createServerPayload(); 358 $this->createServerHeaders(); 359 } 360 } 361 362 /** 363 * @return string the debug information if debug debug mode is on 364 */ 365 function serializeDebug() 366 { 367 global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; 368 369 if ($this->debug) { 370 XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" 371 . $HTTP_RAW_POST_DATA 372 . "\n" . '^^^ END POST DATA ^^^'); 373 } 374 375 if ($XML_RPC_Server_debuginfo != '') { 376 return "<!-- PEAR XML_RPC SERVER DEBUG INFO:\n\n" 377 . $GLOBALS['XML_RPC_func_ereg_replace']('--', '- - ', $XML_RPC_Server_debuginfo) 378 . "-->\n"; 379 } else { 380 return ''; 381 } 382 } 383 384 /** 385 * Sets whether the payload's content gets passed through 386 * mb_convert_encoding() 387 * 388 * Returns PEAR_ERROR object if mb_convert_encoding() isn't available. 389 * 390 * @param int $in where 1 = on, 0 = off 391 * 392 * @return void 393 * 394 * @see XML_RPC_Message::getEncoding() 395 * @since Method available since Release 1.5.1 396 */ 397 function setConvertPayloadEncoding($in) 398 { 399 if ($in && !function_exists('mb_convert_encoding')) { 400 return $this->raiseError('mb_convert_encoding() is not available', 401 XML_RPC_ERROR_PROGRAMMING); 402 } 403 $this->convert_payload_encoding = $in; 404 } 405 406 /** 407 * Sends the response 408 * 409 * The encoding and content-type are determined by 410 * XML_RPC_Message::getEncoding() 411 * 412 * @return void 413 * 414 * @uses XML_RPC_Server::createServerPayload(), 415 * XML_RPC_Server::createServerHeaders() 416 */ 417 function service() 418 { 419 if (!$this->server_payload) { 420 $this->createServerPayload(); 421 } 422 if (!$this->server_headers) { 423 $this->createServerHeaders(); 424 } 425 426 /* 427 * $server_headers needs to remain a string for compatibility with 428 * old scripts using this package, but PHP 4.4.2 no longer allows 429 * line breaks in header() calls. So, we split each header into 430 * an individual call. The initial replace handles the off chance 431 * that someone composed a single header with multiple lines, which 432 * the RFCs allow. 433 */ 434 $this->server_headers = $GLOBALS['XML_RPC_func_ereg_replace']("[\r\n]+[ \t]+", 435 ' ', trim($this->server_headers)); 436 $headers = $GLOBALS['XML_RPC_func_split']("[\r\n]+", $this->server_headers); 437 foreach ($headers as $header) 438 { 439 header($header); 440 } 441 442 print $this->server_payload; 443 } 444 445 /** 446 * Generates the payload and puts it in the $server_payload property 447 * 448 * If XML_RPC_Server::setConvertPayloadEncoding() was set to true, 449 * the payload gets passed through mb_convert_encoding() 450 * to ensure the payload matches the encoding set in the 451 * XML declaration. The encoding type can be manually set via 452 * XML_RPC_Message::setSendEncoding(). 453 * 454 * @return void 455 * 456 * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, 457 * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() 458 * @see XML_RPC_Server::setConvertPayloadEncoding() 459 */ 460 function createServerPayload() 461 { 462 $r = $this->parseRequest(); 463 $this->server_payload = '<?xml version="1.0" encoding="' 464 . $this->encoding . '"?>' . "\n" 465 . $this->serializeDebug() 466 . $r->serialize(); 467 if ($this->convert_payload_encoding) { 468 $this->server_payload = mb_convert_encoding($this->server_payload, 469 $this->encoding); 470 } 471 } 472 473 /** 474 * Determines the HTTP headers and puts them in the $server_headers 475 * property 476 * 477 * @return boolean TRUE if okay, FALSE if $server_payload isn't set. 478 * 479 * @uses XML_RPC_Server::createServerPayload(), 480 * XML_RPC_Server::$server_headers 481 */ 482 function createServerHeaders() 483 { 484 if (!$this->server_payload) { 485 return false; 486 } 487 $this->server_headers = 'Content-Length: ' 488 . strlen($this->server_payload) . "\r\n" 489 . 'Content-Type: text/xml;' 490 . ' charset=' . $this->encoding; 491 return true; 492 } 493 494 /** 495 * @return array 496 */ 497 function verifySignature($in, $sig) 498 { 499 for ($i = 0; $i < sizeof($sig); $i++) { 500 // check each possible signature in turn 501 $cursig = $sig[$i]; 502 if (sizeof($cursig) == $in->getNumParams() + 1) { 503 $itsOK = 1; 504 for ($n = 0; $n < $in->getNumParams(); $n++) { 505 $p = $in->getParam($n); 506 // print "<!-- $p -->\n"; 507 if ($p->kindOf() == 'scalar') { 508 $pt = $p->scalartyp(); 509 } else { 510 $pt = $p->kindOf(); 511 } 512 // $n+1 as first type of sig is return type 513 if ($pt != $cursig[$n+1]) { 514 $itsOK = 0; 515 $pno = $n+1; 516 $wanted = $cursig[$n+1]; 517 $got = $pt; 518 break; 519 } 520 } 521 if ($itsOK) { 522 return array(1); 523 } 524 } 525 } 526 if (isset($wanted)) { 527 return array(0, "Wanted $wanted}, got $got} at param $pno}"); 528 } else { 529 $allowed = array(); 530 foreach ($sig as $val) { 531 end($val); 532 $allowed[] = key($val); 533 } 534 $allowed = array_unique($allowed); 535 $last = count($allowed) - 1; 536 if ($last > 0) { 537 $allowed[$last] = 'or ' . $allowed[$last]; 538 } 539 return array(0, 540 'Signature permits ' . implode(', ', $allowed) 541 . ' parameters but the request had ' 542 . $in->getNumParams()); 543 } 544 } 545 546 /** 547 * @return object a new XML_RPC_Response object 548 * 549 * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding 550 */ 551 function parseRequest($data = '') 552 { 553 global $XML_RPC_xh, $HTTP_RAW_POST_DATA, 554 $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, 555 $XML_RPC_defencoding, $XML_RPC_Server_dmap; 556 557 if ($data == '') { 558 $data = $HTTP_RAW_POST_DATA; 559 } 560 561 $this->encoding = XML_RPC_Message::getEncoding($data); 562 $parser_resource = xml_parser_create($this->encoding); 563 $parser = (int) $parser_resource; 564 565 $XML_RPC_xh[$parser] = array(); 566 $XML_RPC_xh[$parser]['cm'] = 0; 567 $XML_RPC_xh[$parser]['isf'] = 0; 568 $XML_RPC_xh[$parser]['params'] = array(); 569 $XML_RPC_xh[$parser]['method'] = ''; 570 $XML_RPC_xh[$parser]['stack'] = array(); 571 $XML_RPC_xh[$parser]['valuestack'] = array(); 572 573 $plist = ''; 574 575 // decompose incoming XML into request structure 576 577 xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); 578 xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); 579 xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); 580 if (!xml_parse($parser_resource, $data, 1)) { 581 // return XML error as a faultCode 582 $r = new XML_RPC_Response(0, 583 $XML_RPC_errxml+xml_get_error_code($parser_resource), 584 sprintf('XML error: %s at line %d', 585 xml_error_string(xml_get_error_code($parser_resource)), 586 xml_get_current_line_number($parser_resource))); 587 xml_parser_free($parser_resource); 588 } elseif ($XML_RPC_xh[$parser]['isf']>1) { 589 $r = new XML_RPC_Response(0, 590 $XML_RPC_err['invalid_request'], 591 $XML_RPC_str['invalid_request'] 592 . ': ' 593 . $XML_RPC_xh[$parser]['isf_reason']); 594 xml_parser_free($parser_resource); 595 } else { 596 xml_parser_free($parser_resource); 597 $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); 598 // now add parameters in 599 for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { 600 // print '<!-- ' . $XML_RPC_xh[$parser]['params'][$i]. "-->\n"; 601 $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n"; 602 $m->addParam($XML_RPC_xh[$parser]['params'][$i]); 603 } 604 605 if ($this->debug) { 606 XML_RPC_Server_debugmsg($plist); 607 } 608 609 // now to deal with the method 610 $methName = $XML_RPC_xh[$parser]['method']; 611 if (strpos($methName, 'system.') === 0) { 612 $dmap = $XML_RPC_Server_dmap; 613 $sysCall = 1; 614 } else { 615 $dmap = $this->dmap; 616 $sysCall = 0; 617 } 618 619 if (isset($dmap[$methName]['function']) 620 && is_string($dmap[$methName]['function']) 621 && strpos($dmap[$methName]['function'], '::') !== false) 622 { 623 $dmap[$methName]['function'] = 624 explode('::', $dmap[$methName]['function']); 625 } 626 627 if (isset($dmap[$methName]['function']) 628 && is_callable($dmap[$methName]['function'])) 629 { 630 // dispatch if exists 631 if (isset($dmap[$methName]['signature'])) { 632 $sr = $this->verifySignature($m, 633 $dmap[$methName]['signature'] ); 634 } 635 if (!isset($dmap[$methName]['signature']) || $sr[0]) { 636 // if no signature or correct signature 637 if ($sysCall) { 638 $r = call_user_func($dmap[$methName]['function'], $this, $m); 639 } else { 640 $r = call_user_func($dmap[$methName]['function'], $m); 641 } 642 if (!is_a($r, 'XML_RPC_Response')) { 643 $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], 644 $XML_RPC_str['not_response_object']); 645 } 646 } else { 647 $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], 648 $XML_RPC_str['incorrect_params'] 649 . ': ' . $sr[1]); 650 } 651 } else { 652 // else prepare error response 653 $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], 654 $XML_RPC_str['unknown_method']); 655 } 656 } 657 return $r; 658 } 659 660 /** 661 * Echos back the input packet as a string value 662 * 663 * @return void 664 * 665 * Useful for debugging. 666 */ 667 function echoInput() 668 { 669 global $HTTP_RAW_POST_DATA; 670 671 $r = new XML_RPC_Response(0); 672 $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); 673 print $r->serialize(); 674 } 675 } 676 677 /* 678 * Local variables: 679 * tab-width: 4 680 * c-basic-offset: 4 681 * c-hanging-comment-ender-p: nil 682 * End: 683 */ 684 685 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Wed Nov 21 12:27:40 2007 | par Balluche grâce à PHPXref 0.7 |
|