Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like xmlrpc_server often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use xmlrpc_server, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
433 | class xmlrpc_server |
||
434 | { |
||
435 | /** |
||
436 | * Array defining php functions exposed as xmlrpc methods by this server |
||
437 | * @access private |
||
438 | */ |
||
439 | var $dmap=array(); |
||
440 | /** |
||
441 | * Defines how functions in dmap will be invoked: either using an xmlrpc msg object |
||
442 | * or plain php values. |
||
443 | * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals' |
||
444 | */ |
||
445 | var $functions_parameters_type='xmlrpcvals'; |
||
446 | /** |
||
447 | * Option used for fine-tuning the encoding the php values returned from |
||
448 | * functions registered in the dispatch map when the functions_parameters_types |
||
449 | * member is set to 'phpvals' |
||
450 | * @see php_xmlrpc_encode for a list of values |
||
451 | */ |
||
452 | var $phpvals_encoding_options = array( 'auto_dates' ); |
||
453 | /// controls whether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3 |
||
454 | var $debug = 1; |
||
455 | /** |
||
456 | * Controls behaviour of server when invoked user function throws an exception: |
||
457 | * 0 = catch it and return an 'internal error' xmlrpc response (default) |
||
458 | * 1 = catch it and return an xmlrpc response with the error corresponding to the exception |
||
459 | * 2 = allow the exception to float to the upper layers |
||
460 | */ |
||
461 | var $exception_handling = 0; |
||
462 | /** |
||
463 | * When set to true, it will enable HTTP compression of the response, in case |
||
464 | * the client has declared its support for compression in the request. |
||
465 | */ |
||
466 | var $compress_response = false; |
||
467 | /** |
||
468 | * List of http compression methods accepted by the server for requests. |
||
469 | * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib |
||
470 | */ |
||
471 | var $accepted_compression = array(); |
||
472 | /// shall we serve calls to system.* methods? |
||
473 | var $allow_system_funcs = true; |
||
474 | /// list of charset encodings natively accepted for requests |
||
475 | var $accepted_charset_encodings = array(); |
||
476 | /** |
||
477 | * charset encoding to be used for response. |
||
478 | * NB: if we can, we will convert the generated response from internal_encoding to the intended one. |
||
479 | * can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled), |
||
480 | * null (leave unspecified in response, convert output stream to US_ASCII), |
||
481 | * 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed), |
||
482 | * or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway). |
||
483 | * NB: pretty dangerous if you accept every charset and do not have mbstring enabled) |
||
484 | */ |
||
485 | var $response_charset_encoding = ''; |
||
486 | /** |
||
487 | * Storage for internal debug info |
||
488 | * @access private |
||
489 | */ |
||
490 | var $debug_info = ''; |
||
491 | /** |
||
492 | * Extra data passed at runtime to method handling functions. Used only by EPI layer |
||
493 | */ |
||
494 | var $user_data = null; |
||
495 | |||
496 | /** |
||
497 | * @param array $dispmap the dispatch map with definition of exposed services |
||
498 | * @param boolean $servicenow set to false to prevent the server from running upon construction |
||
499 | */ |
||
500 | function __construct($dispMap=null, $serviceNow=true) |
||
501 | { |
||
502 | // if ZLIB is enabled, let the server by default accept compressed requests, |
||
503 | // and compress responses sent to clients that support them |
||
504 | if(function_exists('gzinflate')) |
||
505 | { |
||
506 | $this->accepted_compression = array('gzip', 'deflate'); |
||
507 | $this->compress_response = true; |
||
508 | } |
||
509 | |||
510 | // by default the xml parser can support these 3 charset encodings |
||
511 | $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); |
||
512 | |||
513 | // dispMap is a dispatch array of methods |
||
514 | // mapped to function names and signatures |
||
515 | // if a method |
||
516 | // doesn't appear in the map then an unknown |
||
517 | // method error is generated |
||
518 | /* milosch - changed to make passing dispMap optional. |
||
519 | * instead, you can use the class add_to_map() function |
||
520 | * to add functions manually (borrowed from SOAPX4) |
||
521 | */ |
||
522 | if($dispMap) |
||
523 | { |
||
524 | $this->dmap = $dispMap; |
||
525 | if($serviceNow) |
||
526 | { |
||
527 | $this->service(); |
||
528 | } |
||
529 | } |
||
530 | } |
||
531 | |||
532 | /** |
||
533 | * @deprecated |
||
534 | */ |
||
535 | function xmlrpc_client($dispMap=null, $serviceNow=true) |
||
536 | { |
||
537 | self::__construct($dispMap, $serviceNow); |
||
538 | } |
||
539 | |||
540 | /** |
||
541 | * Set debug level of server. |
||
542 | * @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments) |
||
543 | * 0 = no debug info, |
||
544 | * 1 = msgs set from user with debugmsg(), |
||
545 | * 2 = add complete xmlrpc request (headers and body), |
||
546 | * 3 = add also all processing warnings happened during method processing |
||
547 | * (NB: this involves setting a custom error handler, and might interfere |
||
548 | * with the standard processing of the php function exposed as method. In |
||
549 | * particular, triggering an USER_ERROR level error will not halt script |
||
550 | * execution anymore, but just end up logged in the xmlrpc response) |
||
551 | * Note that info added at level 2 and 3 will be base64 encoded |
||
552 | * @access public |
||
553 | */ |
||
554 | function setDebug($in) |
||
555 | { |
||
556 | $this->debug=$in; |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * Return a string with the serialized representation of all debug info |
||
561 | * @param string $charset_encoding the target charset encoding for the serialization |
||
562 | * @return string an XML comment (or two) |
||
563 | */ |
||
564 | function serializeDebug($charset_encoding='') |
||
565 | { |
||
566 | // Tough encoding problem: which internal charset should we assume for debug info? |
||
567 | // It might contain a copy of raw data received from client, ie with unknown encoding, |
||
568 | // intermixed with php generated data and user generated data... |
||
569 | // so we split it: system debug is base 64 encoded, |
||
570 | // user debug info should be encoded by the end user using the INTERNAL_ENCODING |
||
571 | $out = ''; |
||
572 | if ($this->debug_info != '') |
||
573 | { |
||
574 | $out .= "<!-- SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n-->\n"; |
||
575 | } |
||
576 | if($GLOBALS['_xmlrpc_debuginfo']!='') |
||
577 | { |
||
578 | |||
579 | $out .= "<!-- DEBUG INFO:\n" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n"; |
||
580 | // NB: a better solution MIGHT be to use CDATA, but we need to insert it |
||
581 | // into return payload AFTER the beginning tag |
||
582 | //$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n"; |
||
583 | } |
||
584 | return $out; |
||
585 | } |
||
586 | |||
587 | /** |
||
588 | * Execute the xmlrpc request, printing the response |
||
589 | * @param string $data the request body. If null, the http POST request will be examined |
||
590 | * @return xmlrpcresp the response object (usually not used by caller...) |
||
591 | * @access public |
||
592 | */ |
||
593 | function service($data=null, $return_payload=false) |
||
594 | { |
||
595 | if ($data === null) |
||
596 | { |
||
597 | // workaround for a known bug in php ver. 5.2.2 that broke $HTTP_RAW_POST_DATA |
||
598 | $data = file_get_contents('php://input'); |
||
599 | } |
||
600 | $raw_data = $data; |
||
601 | |||
602 | // reset internal debug info |
||
603 | $this->debug_info = ''; |
||
604 | |||
605 | // Echo back what we received, before parsing it |
||
606 | if($this->debug > 1) |
||
607 | { |
||
608 | $this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++"); |
||
609 | } |
||
610 | |||
611 | $r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding); |
||
612 | if (!$r) |
||
613 | { |
||
614 | $r=$this->parseRequest($data, $req_charset); |
||
615 | } |
||
616 | |||
617 | // save full body of request into response, for more debugging usages |
||
618 | $r->raw_data = $raw_data; |
||
619 | |||
620 | if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors']) |
||
621 | { |
||
622 | $this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" . |
||
623 | $GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++"); |
||
624 | } |
||
625 | |||
626 | $payload=$this->xml_header($resp_charset); |
||
627 | if($this->debug > 0) |
||
628 | { |
||
629 | $payload = $payload . $this->serializeDebug($resp_charset); |
||
630 | } |
||
631 | |||
632 | // G. Giunta 2006-01-27: do not create response serialization if it has |
||
633 | // already happened. Helps building json magic |
||
634 | if (empty($r->payload)) |
||
635 | { |
||
636 | $r->serialize($resp_charset); |
||
637 | } |
||
638 | $payload = $payload . $r->payload; |
||
639 | |||
640 | if ($return_payload) |
||
641 | { |
||
642 | return $payload; |
||
643 | } |
||
644 | |||
645 | // if we get a warning/error that has output some text before here, then we cannot |
||
646 | // add a new header. We cannot say we are sending xml, either... |
||
647 | if(!headers_sent()) |
||
648 | { |
||
649 | header('Content-Type: '.$r->content_type); |
||
650 | // we do not know if client actually told us an accepted charset, but if he did |
||
651 | // we have to tell him what we did |
||
652 | header("Vary: Accept-Charset"); |
||
653 | |||
654 | // http compression of output: only |
||
655 | // if we can do it, and we want to do it, and client asked us to, |
||
656 | // and php ini settings do not force it already |
||
657 | $php_no_self_compress = !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler'); |
||
658 | if($this->compress_response && function_exists('gzencode') && $resp_encoding != '' |
||
659 | && $php_no_self_compress) |
||
660 | { |
||
661 | if(strpos($resp_encoding, 'gzip') !== false) |
||
662 | { |
||
663 | $payload = gzencode($payload); |
||
664 | header("Content-Encoding: gzip"); |
||
665 | header("Vary: Accept-Encoding"); |
||
666 | } |
||
667 | elseif (strpos($resp_encoding, 'deflate') !== false) |
||
668 | { |
||
669 | $payload = gzcompress($payload); |
||
670 | header("Content-Encoding: deflate"); |
||
671 | header("Vary: Accept-Encoding"); |
||
672 | } |
||
673 | } |
||
674 | |||
675 | // do not ouput content-length header if php is compressing output for us: |
||
676 | // it will mess up measurements |
||
677 | if($php_no_self_compress) |
||
678 | { |
||
679 | header('Content-Length: ' . (int)strlen($payload)); |
||
680 | } |
||
681 | } |
||
682 | else |
||
683 | { |
||
684 | error_log('XML-RPC: '.__METHOD__.': http headers already sent before response is fully generated. Check for php warning or error messages'); |
||
685 | } |
||
686 | |||
687 | print $payload; |
||
688 | |||
689 | // return request, in case subclasses want it |
||
690 | return $r; |
||
691 | } |
||
692 | |||
693 | /** |
||
694 | * Add a method to the dispatch map |
||
695 | * @param string $methodname the name with which the method will be made available |
||
696 | * @param string $function the php function that will get invoked |
||
697 | * @param array $sig the array of valid method signatures |
||
698 | * @param string $doc method documentation |
||
699 | * @param array $sigdoc the array of valid method signatures docs (one string per param, one for return type) |
||
700 | * @access public |
||
701 | */ |
||
702 | function add_to_map($methodname,$function,$sig=null,$doc=false,$sigdoc=false) |
||
703 | { |
||
704 | $this->dmap[$methodname] = array( |
||
705 | 'function' => $function, |
||
706 | 'docstring' => $doc |
||
707 | ); |
||
708 | if ($sig) |
||
709 | { |
||
710 | $this->dmap[$methodname]['signature'] = $sig; |
||
711 | } |
||
712 | if ($sigdoc) |
||
713 | { |
||
714 | $this->dmap[$methodname]['signature_docs'] = $sigdoc; |
||
715 | } |
||
716 | } |
||
717 | |||
718 | /** |
||
719 | * Verify type and number of parameters received against a list of known signatures |
||
720 | * @param array $in array of either xmlrpcval objects or xmlrpc type definitions |
||
721 | * @param array $sig array of known signatures to match against |
||
722 | * @return array |
||
723 | * @access private |
||
724 | */ |
||
725 | function verifySignature($in, $sig) |
||
726 | { |
||
727 | // check each possible signature in turn |
||
728 | if (is_object($in)) |
||
729 | { |
||
730 | $numParams = $in->getNumParams(); |
||
731 | } |
||
732 | else |
||
733 | { |
||
734 | $numParams = count($in); |
||
735 | } |
||
736 | foreach($sig as $cursig) |
||
737 | { |
||
738 | if(count($cursig)==$numParams+1) |
||
739 | { |
||
740 | $itsOK=1; |
||
741 | for($n=0; $n<$numParams; $n++) |
||
742 | { |
||
743 | if (is_object($in)) |
||
744 | { |
||
745 | $p=$in->getParam($n); |
||
746 | if($p->kindOf() == 'scalar') |
||
747 | { |
||
748 | $pt=$p->scalartyp(); |
||
749 | } |
||
750 | else |
||
751 | { |
||
752 | $pt=$p->kindOf(); |
||
753 | } |
||
754 | } |
||
755 | else |
||
756 | { |
||
757 | $pt= $in[$n] == 'i4' ? 'int' : strtolower($in[$n]); // dispatch maps never use i4... |
||
758 | } |
||
759 | |||
760 | // param index is $n+1, as first member of sig is return type |
||
761 | if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue']) |
||
762 | { |
||
763 | $itsOK=0; |
||
764 | $pno=$n+1; |
||
765 | $wanted=$cursig[$n+1]; |
||
766 | $got=$pt; |
||
767 | break; |
||
768 | } |
||
769 | } |
||
770 | if($itsOK) |
||
771 | { |
||
772 | return array(1,''); |
||
773 | } |
||
774 | } |
||
775 | } |
||
776 | if(isset($wanted)) |
||
777 | { |
||
778 | return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); |
||
779 | } |
||
780 | else |
||
781 | { |
||
782 | return array(0, "No method signature matches number of parameters"); |
||
783 | } |
||
784 | } |
||
785 | |||
786 | /** |
||
787 | * Parse http headers received along with xmlrpc request. If needed, inflate request |
||
788 | * @return mixed null on success or an xmlrpcresp |
||
789 | * @access private |
||
790 | */ |
||
791 | function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression) |
||
792 | { |
||
793 | // check if $_SERVER is populated: it might have been disabled via ini file |
||
794 | // (this is true even when in CLI mode) |
||
795 | if (count($_SERVER) == 0) |
||
796 | { |
||
797 | error_log('XML-RPC: '.__METHOD__.': cannot parse request headers as $_SERVER is not populated'); |
||
798 | } |
||
799 | |||
800 | if($this->debug > 1) |
||
801 | { |
||
802 | if(function_exists('getallheaders')) |
||
803 | { |
||
804 | $this->debugmsg(''); // empty line |
||
805 | foreach(getallheaders() as $name => $val) |
||
806 | { |
||
807 | $this->debugmsg("HEADER: $name: $val"); |
||
808 | } |
||
809 | } |
||
810 | |||
811 | } |
||
812 | |||
813 | if(isset($_SERVER['HTTP_CONTENT_ENCODING'])) |
||
814 | { |
||
815 | $content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']); |
||
816 | } |
||
817 | else |
||
818 | { |
||
819 | $content_encoding = ''; |
||
820 | } |
||
821 | |||
822 | // check if request body has been compressed and decompress it |
||
823 | if($content_encoding != '' && strlen($data)) |
||
824 | { |
||
825 | if($content_encoding == 'deflate' || $content_encoding == 'gzip') |
||
826 | { |
||
827 | // if decoding works, use it. else assume data wasn't gzencoded |
||
828 | if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression)) |
||
829 | { |
||
830 | if($content_encoding == 'deflate' && $degzdata = @gzuncompress($data)) |
||
831 | { |
||
832 | $data = $degzdata; |
||
833 | if($this->debug > 1) |
||
834 | { |
||
835 | $this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++"); |
||
836 | } |
||
837 | } |
||
838 | elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10))) |
||
839 | { |
||
840 | $data = $degzdata; |
||
841 | if($this->debug > 1) |
||
842 | $this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++"); |
||
843 | } |
||
844 | else |
||
845 | { |
||
846 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']); |
||
847 | return $r; |
||
848 | } |
||
849 | } |
||
850 | else |
||
851 | { |
||
852 | //error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); |
||
853 | $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']); |
||
854 | return $r; |
||
855 | } |
||
856 | } |
||
857 | } |
||
858 | |||
859 | // check if client specified accepted charsets, and if we know how to fulfill |
||
860 | // the request |
||
861 | if ($this->response_charset_encoding == 'auto') |
||
862 | { |
||
863 | $resp_encoding = ''; |
||
864 | if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) |
||
865 | { |
||
866 | // here we should check if we can match the client-requested encoding |
||
867 | // with the encodings we know we can generate. |
||
868 | /// @todo we should parse q=0.x preferences instead of getting first charset specified... |
||
869 | $client_accepted_charsets = explode(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET'])); |
||
870 | // Give preference to internal encoding |
||
871 | $known_charsets = array($GLOBALS['xmlrpc_internalencoding'], 'UTF-8', 'ISO-8859-1', 'US-ASCII'); |
||
872 | foreach ($known_charsets as $charset) |
||
873 | { |
||
874 | foreach ($client_accepted_charsets as $accepted) |
||
875 | if (strpos($accepted, $charset) === 0) |
||
876 | { |
||
877 | $resp_encoding = $charset; |
||
878 | break; |
||
879 | } |
||
880 | if ($resp_encoding) |
||
881 | break; |
||
882 | } |
||
883 | } |
||
884 | } |
||
885 | else |
||
886 | { |
||
887 | $resp_encoding = $this->response_charset_encoding; |
||
888 | } |
||
889 | |||
890 | if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) |
||
891 | { |
||
892 | $resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING']; |
||
893 | } |
||
894 | else |
||
895 | { |
||
896 | $resp_compression = ''; |
||
897 | } |
||
898 | |||
899 | // 'guestimate' request encoding |
||
900 | /// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check??? |
||
901 | $req_encoding = guess_encoding(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '', |
||
902 | $data); |
||
903 | |||
904 | return null; |
||
905 | } |
||
906 | |||
907 | /** |
||
908 | * Parse an xml chunk containing an xmlrpc request and execute the corresponding |
||
909 | * php function registered with the server |
||
910 | * @param string $data the xml request |
||
911 | * @param string $req_encoding (optional) the charset encoding of the xml request |
||
912 | * @return xmlrpcresp |
||
913 | * @access private |
||
914 | */ |
||
915 | function parseRequest($data, $req_encoding='') |
||
916 | { |
||
917 | // 2005/05/07 commented and moved into caller function code |
||
918 | //if($data=='') |
||
919 | //{ |
||
920 | // $data=$GLOBALS['HTTP_RAW_POST_DATA']; |
||
921 | //} |
||
922 | |||
923 | // G. Giunta 2005/02/13: we do NOT expect to receive html entities |
||
924 | // so we do not try to convert them into xml character entities |
||
925 | //$data = xmlrpc_html_entity_xlate($data); |
||
926 | |||
927 | $GLOBALS['_xh']=array(); |
||
928 | $GLOBALS['_xh']['ac']=''; |
||
929 | $GLOBALS['_xh']['stack']=array(); |
||
930 | $GLOBALS['_xh']['valuestack'] = array(); |
||
931 | $GLOBALS['_xh']['params']=array(); |
||
932 | $GLOBALS['_xh']['pt']=array(); |
||
933 | $GLOBALS['_xh']['isf']=0; |
||
934 | $GLOBALS['_xh']['isf_reason']=''; |
||
935 | $GLOBALS['_xh']['method']=false; // so we can check later if we got a methodname or not |
||
936 | $GLOBALS['_xh']['rt']=''; |
||
937 | |||
938 | // decompose incoming XML into request structure |
||
939 | |||
940 | if ($req_encoding != '') |
||
941 | { |
||
942 | // Since parsing will fail if charset is not specified in the xml prologue, |
||
943 | // the encoding is not UTF8 and there are non-ascii chars in the text, we try to work round that... |
||
944 | // The following code might be better for mb_string enabled installs, but |
||
945 | // makes the lib about 200% slower... |
||
946 | //if (!is_valid_charset($req_encoding, array('UTF-8'))) |
||
947 | if (!in_array($req_encoding, array('UTF-8', 'US-ASCII')) && !has_encoding($data)) { |
||
948 | if ($req_encoding == 'ISO-8859-1') { |
||
949 | $data = utf8_encode($data); |
||
950 | } else { |
||
951 | if (extension_loaded('mbstring')) { |
||
952 | $data = mb_convert_encoding($data, 'UTF-8', $req_encoding); |
||
953 | } else { |
||
954 | error_log('XML-RPC: ' . __METHOD__ . ': invalid charset encoding of received request: ' . $req_encoding); |
||
955 | } |
||
956 | } |
||
957 | } |
||
958 | } |
||
959 | |||
960 | $parser = xml_parser_create(); |
||
961 | xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); |
||
962 | // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell |
||
963 | // the xml parser to give us back data in the expected charset |
||
964 | // What if internal encoding is not in one of the 3 allowed? |
||
965 | // we use the broadest one, ie. utf8 |
||
966 | // This allows to send data which is native in various charset, |
||
967 | // by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding |
||
968 | if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) |
||
969 | { |
||
970 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); |
||
971 | } |
||
972 | else |
||
973 | { |
||
974 | xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']); |
||
975 | } |
||
976 | |||
977 | if ($this->functions_parameters_type != 'xmlrpcvals') |
||
978 | xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast'); |
||
979 | else |
||
980 | xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); |
||
981 | xml_set_character_data_handler($parser, 'xmlrpc_cd'); |
||
982 | xml_set_default_handler($parser, 'xmlrpc_dh'); |
||
983 | if(!xml_parse($parser, $data, 1)) |
||
984 | { |
||
985 | // return XML error as a faultCode |
||
986 | $r=new xmlrpcresp(0, |
||
987 | $GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser), |
||
988 | sprintf('XML error: %s at line %d, column %d', |
||
989 | xml_error_string(xml_get_error_code($parser)), |
||
990 | xml_get_current_line_number($parser), xml_get_current_column_number($parser))); |
||
991 | xml_parser_free($parser); |
||
992 | } |
||
993 | elseif ($GLOBALS['_xh']['isf']) |
||
994 | { |
||
995 | xml_parser_free($parser); |
||
996 | $r=new xmlrpcresp(0, |
||
997 | $GLOBALS['xmlrpcerr']['invalid_request'], |
||
998 | $GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']); |
||
999 | } |
||
1000 | else |
||
1001 | { |
||
1002 | xml_parser_free($parser); |
||
1003 | // small layering violation in favor of speed and memory usage: |
||
1004 | // we should allow the 'execute' method handle this, but in the |
||
1005 | // most common scenario (xmlrpcvals type server with some methods |
||
1006 | // registered as phpvals) that would mean a useless encode+decode pass |
||
1007 | if ($this->functions_parameters_type != 'xmlrpcvals' || (isset($this->dmap[$GLOBALS['_xh']['method']]['parameters_type']) && ($this->dmap[$GLOBALS['_xh']['method']]['parameters_type'] == 'phpvals'))) |
||
1008 | { |
||
1009 | if($this->debug > 1) |
||
1010 | { |
||
1011 | $this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++"); |
||
1012 | } |
||
1013 | $r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']); |
||
1014 | } |
||
1015 | else |
||
1016 | { |
||
1017 | // build an xmlrpcmsg object with data parsed from xml |
||
1018 | $m=new xmlrpcmsg($GLOBALS['_xh']['method']); |
||
1019 | // now add parameters in |
||
1020 | for($i=0; $i<count($GLOBALS['_xh']['params']); $i++) |
||
1021 | { |
||
1022 | $m->addParam($GLOBALS['_xh']['params'][$i]); |
||
1023 | } |
||
1024 | |||
1025 | if($this->debug > 1) |
||
1026 | { |
||
1027 | $this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++"); |
||
1028 | } |
||
1029 | $r = $this->execute($m); |
||
1030 | } |
||
1031 | } |
||
1032 | return $r; |
||
1033 | } |
||
1034 | |||
1035 | /** |
||
1036 | * Execute a method invoked by the client, checking parameters used |
||
1037 | * @param mixed $m either an xmlrpcmsg obj or a method name |
||
1038 | * @param array $params array with method parameters as php types (if m is method name only) |
||
1039 | * @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only) |
||
1040 | * @return xmlrpcresp |
||
1041 | * @access private |
||
1042 | */ |
||
1043 | function execute($m, $params=null, $paramtypes=null) |
||
1211 | } |
||
1212 | |||
1213 | /** |
||
1214 | * add a string to the 'internal debug message' (separate from 'user debug message') |
||
1215 | * @param string $string |
||
1216 | * @access private |
||
1217 | */ |
||
1218 | function debugmsg($string) |
||
1221 | } |
||
1222 | |||
1223 | /** |
||
1224 | * @access private |
||
1225 | */ |
||
1226 | function xml_header($charset_encoding='') |
||
1227 | { |
||
1228 | if ($charset_encoding != '') |
||
1229 | { |
||
1230 | return "<?xml version=\"1.0\" encoding=\"$charset_encoding\"?" . ">\n"; |
||
1231 | } |
||
1232 | else |
||
1233 | { |
||
1234 | return "<?xml version=\"1.0\"?" . ">\n"; |
||
1235 | } |
||
1236 | } |
||
1237 | |||
1238 | /** |
||
1239 | * A debugging routine: just echoes back the input packet as a string value |
||
1240 | * @deprecated |
||
1241 | */ |
||
1242 | function echoInput() |
||
1246 | } |
||
1247 | } |
||
1248 | ?> |
||
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.