From 621782736d0b482fc437b2abbf94ef29b73eaaec Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 09:52:24 +0200 Subject: [PATCH 01/14] Fixes XML-RPC compatibility with PHP 8 - PR6264 --- system/libraries/Xmlrpc.php | 161 +++++++++++++++++------------------ system/libraries/Xmlrpcs.php | 13 ++- 2 files changed, 83 insertions(+), 91 deletions(-) diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 6b9ad4696a0..12387681699 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1153,8 +1153,7 @@ public function parseResponse($fp) //------------------------------------- $parser = xml_parser_create($this->xmlrpc_defencoding); - $pname = spl_object_id($parser); - $this->xh[$pname] = array( + $this->xh = array( 'isf' => 0, 'ac' => '', 'headers' => array(), @@ -1177,7 +1176,7 @@ public function parseResponse($fp) { break; } - $this->xh[$pname]['headers'][] = $line; + $this->xh['headers'][] = $line; } $data = implode("\r\n", $lines); @@ -1195,18 +1194,18 @@ public function parseResponse($fp) xml_parser_free($parser); // Got ourselves some badness, it seems - if ($this->xh[$pname]['isf'] > 1) + if ($this->xh['isf'] > 1) { if ($this->debug === TRUE) { - echo "---Invalid Return---\n".$this->xh[$pname]['isf_reason']."---Invalid Return---\n\n"; + echo "---Invalid Return---\n".$this->xh['isf_reason']."---Invalid Return---\n\n"; } - return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']); + return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh['isf_reason']); } - elseif ( ! is_object($this->xh[$pname]['value'])) + elseif ( ! is_object($this->xh['value'])) { - return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']); + return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh['isf_reason']); } // Display XML content for debugging @@ -1214,10 +1213,10 @@ public function parseResponse($fp) { echo '
';
 
-			if (count($this->xh[$pname]['headers']) > 0)
+			if (count($this->xh['headers']) > 0)
 			{
 				echo "---HEADERS---\n";
-				foreach ($this->xh[$pname]['headers'] as $header)
+				foreach ($this->xh['headers'] as $header)
 				{
 					echo $header."\n";
 				}
@@ -1225,13 +1224,13 @@ public function parseResponse($fp)
 			}
 
 			echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n";
-			var_dump($this->xh[$pname]['value']);
+			var_dump($this->xh['value']);
 			echo "\n---END PARSED---
"; } // Send response - $v = $this->xh[$pname]['value']; - if ($this->xh[$pname]['isf']) + $v = $this->xh['value']; + if ($this->xh['isf']) { $errno_v = $v->me['struct']['faultCode']; $errstr_v = $v->me['struct']['faultString']; @@ -1250,7 +1249,7 @@ public function parseResponse($fp) $r = new XML_RPC_Response($v); } - $r->headers = $this->xh[$pname]['headers']; + $r->headers = $this->xh['headers']; return $r; } @@ -1281,26 +1280,24 @@ public function parseResponse($fp) */ public function open_tag($the_parser, $name) { - $the_parser = spl_object_id($the_parser); - // If invalid nesting, then return - if ($this->xh[$the_parser]['isf'] > 1) return; + if ($this->xh['isf'] > 1) return; // Evaluate and check for correct nesting of XML elements - if (count($this->xh[$the_parser]['stack']) === 0) + if (count($this->xh['stack']) === 0) { if ($name !== 'METHODRESPONSE' && $name !== 'METHODCALL') { - $this->xh[$the_parser]['isf'] = 2; - $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing'; + $this->xh['isf'] = 2; + $this->xh['isf_reason'] = 'Top level XML-RPC element is missing'; return; } } // not top level element: see if parent is OK - elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE)) + elseif ( ! in_array($this->xh['stack'][0], $this->valid_parents[$name], TRUE)) { - $this->xh[$the_parser]['isf'] = 2; - $this->xh[$the_parser]['isf_reason'] = 'XML-RPC element '.$name.' cannot be child of '.$this->xh[$the_parser]['stack'][0]; + $this->xh['isf'] = 2; + $this->xh['isf_reason'] = 'XML-RPC element '.$name.' cannot be child of '.$this->xh['stack'][0]; return; } @@ -1310,22 +1307,22 @@ public function open_tag($the_parser, $name) case 'ARRAY': // Creates array for child elements $cur_val = array('value' => array(), 'type' => $name); - array_unshift($this->xh[$the_parser]['valuestack'], $cur_val); + array_unshift($this->xh['valuestack'], $cur_val); break; case 'METHODNAME': case 'NAME': - $this->xh[$the_parser]['ac'] = ''; + $this->xh['ac'] = ''; break; case 'FAULT': - $this->xh[$the_parser]['isf'] = 1; + $this->xh['isf'] = 1; break; case 'PARAM': - $this->xh[$the_parser]['value'] = NULL; + $this->xh['value'] = NULL; break; case 'VALUE': - $this->xh[$the_parser]['vt'] = 'value'; - $this->xh[$the_parser]['ac'] = ''; - $this->xh[$the_parser]['lv'] = 1; + $this->xh['vt'] = 'value'; + $this->xh['ac'] = ''; + $this->xh['lv'] = 1; break; case 'I4': case 'INT': @@ -1334,23 +1331,23 @@ public function open_tag($the_parser, $name) case 'DOUBLE': case 'DATETIME.ISO8601': case 'BASE64': - if ($this->xh[$the_parser]['vt'] !== 'value') + if ($this->xh['vt'] !== 'value') { //two data elements inside a value: an error occurred! - $this->xh[$the_parser]['isf'] = 2; - $this->xh[$the_parser]['isf_reason'] = 'There is a '.$name.' element following a ' - .$this->xh[$the_parser]['vt'].' element inside a single value'; + $this->xh['isf'] = 2; + $this->xh['isf_reason'] = 'There is a '.$name.' element following a ' + .$this->xh['vt'].' element inside a single value'; return; } - $this->xh[$the_parser]['ac'] = ''; + $this->xh['ac'] = ''; break; case 'MEMBER': // Set name of to nothing to prevent errors later if no is found - $this->xh[$the_parser]['valuestack'][0]['name'] = ''; + $this->xh['valuestack'][0]['name'] = ''; // Set NULL value to check to see if value passed for this param/member - $this->xh[$the_parser]['value'] = NULL; + $this->xh['value'] = NULL; break; case 'DATA': case 'METHODCALL': @@ -1360,15 +1357,15 @@ public function open_tag($the_parser, $name) break; default: /// An Invalid Element is Found, so we have trouble - $this->xh[$the_parser]['isf'] = 2; - $this->xh[$the_parser]['isf_reason'] = 'Invalid XML-RPC element found: '.$name; + $this->xh['isf'] = 2; + $this->xh['isf_reason'] = 'Invalid XML-RPC element found: '.$name; break; } // Add current element name to stack, to allow validation of nesting - array_unshift($this->xh[$the_parser]['stack'], $name); + array_unshift($this->xh['stack'], $name); - $name === 'VALUE' OR $this->xh[$the_parser]['lv'] = 0; + $name === 'VALUE' OR $this->xh['lv'] = 0; } // -------------------------------------------------------------------- @@ -1382,27 +1379,25 @@ public function open_tag($the_parser, $name) */ public function closing_tag($the_parser, $name) { - $the_parser = spl_object_id($the_parser); - - if ($this->xh[$the_parser]['isf'] > 1) return; + if ($this->xh['isf'] > 1) return; // Remove current element from stack and set variable // NOTE: If the XML validates, then we do not have to worry about // the opening and closing of elements. Nesting is checked on the opening // tag so we be safe there as well. - $curr_elem = array_shift($this->xh[$the_parser]['stack']); + $curr_elem = array_shift($this->xh['stack']); switch ($name) { case 'STRUCT': case 'ARRAY': - $cur_val = array_shift($this->xh[$the_parser]['valuestack']); - $this->xh[$the_parser]['value'] = isset($cur_val['values']) ? $cur_val['values'] : array(); - $this->xh[$the_parser]['vt'] = strtolower($name); + $cur_val = array_shift($this->xh['valuestack']); + $this->xh['value'] = isset($cur_val['values']) ? $cur_val['values'] : array(); + $this->xh['vt'] = strtolower($name); break; case 'NAME': - $this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac']; + $this->xh['valuestack'][0]['name'] = $this->xh['ac']; break; case 'BOOLEAN': case 'I4': @@ -1411,87 +1406,87 @@ public function closing_tag($the_parser, $name) case 'DOUBLE': case 'DATETIME.ISO8601': case 'BASE64': - $this->xh[$the_parser]['vt'] = strtolower($name); + $this->xh['vt'] = strtolower($name); if ($name === 'STRING') { - $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; + $this->xh['value'] = $this->xh['ac']; } elseif ($name === 'DATETIME.ISO8601') { - $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime; - $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; + $this->xh['vt'] = $this->xmlrpcDateTime; + $this->xh['value'] = $this->xh['ac']; } elseif ($name === 'BASE64') { - $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']); + $this->xh['value'] = base64_decode($this->xh['ac']); } elseif ($name === 'BOOLEAN') { // Translated BOOLEAN values to TRUE AND FALSE - $this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac']; + $this->xh['value'] = (bool) $this->xh['ac']; } elseif ($name=='DOUBLE') { // we have a DOUBLE // we must check that only 0123456789-. are characters here - $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac']) - ? (float) $this->xh[$the_parser]['ac'] + $this->xh['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh['ac']) + ? (float) $this->xh['ac'] : 'ERROR_NON_NUMERIC_FOUND'; } else { // we have an I4/INT // we must check that only 0123456789- are characters here - $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac']) - ? (int) $this->xh[$the_parser]['ac'] + $this->xh['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh['ac']) + ? (int) $this->xh['ac'] : 'ERROR_NON_NUMERIC_FOUND'; } - $this->xh[$the_parser]['ac'] = ''; - $this->xh[$the_parser]['lv'] = 3; // indicate we've found a value + $this->xh['ac'] = ''; + $this->xh['lv'] = 3; // indicate we've found a value break; case 'VALUE': // This if() detects if no scalar was inside - if ($this->xh[$the_parser]['vt'] == 'value') + if ($this->xh['vt'] == 'value') { - $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; - $this->xh[$the_parser]['vt'] = $this->xmlrpcString; + $this->xh['value'] = $this->xh['ac']; + $this->xh['vt'] = $this->xmlrpcString; } // build the XML-RPC value out of the data received, and substitute it - $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']); + $temp = new XML_RPC_Values($this->xh['value'], $this->xh['vt']); - if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] === 'ARRAY') + if (count($this->xh['valuestack']) && $this->xh['valuestack'][0]['type'] === 'ARRAY') { // Array - $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp; + $this->xh['valuestack'][0]['values'][] = $temp; } else { // Struct - $this->xh[$the_parser]['value'] = $temp; + $this->xh['value'] = $temp; } break; case 'MEMBER': - $this->xh[$the_parser]['ac'] = ''; + $this->xh['ac'] = ''; // If value add to array in the stack for the last element built - if ($this->xh[$the_parser]['value']) + if ($this->xh['value']) { - $this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value']; + $this->xh['valuestack'][0]['values'][$this->xh['valuestack'][0]['name']] = $this->xh['value']; } break; case 'DATA': - $this->xh[$the_parser]['ac'] = ''; + $this->xh['ac'] = ''; break; case 'PARAM': - if ($this->xh[$the_parser]['value']) + if ($this->xh['value']) { - $this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value']; + $this->xh['params'][] = $this->xh['value']; } break; case 'METHODNAME': - $this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']); + $this->xh['method'] = ltrim($this->xh['ac']); break; case 'PARAMS': case 'FAULT': @@ -1516,24 +1511,22 @@ public function closing_tag($the_parser, $name) */ public function character_data($the_parser, $data) { - $the_parser = spl_object_id($the_parser); - - if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already + if ($this->xh['isf'] > 1) return; // XML Fault found already // If a value has not been found - if ($this->xh[$the_parser]['lv'] !== 3) + if ($this->xh['lv'] !== 3) { - if ($this->xh[$the_parser]['lv'] === 1) + if ($this->xh['lv'] === 1) { - $this->xh[$the_parser]['lv'] = 2; // Found a value + $this->xh['lv'] = 2; // Found a value } - if ( ! isset($this->xh[$the_parser]['ac'])) + if ( ! isset($this->xh['ac'])) { - $this->xh[$the_parser]['ac'] = ''; + $this->xh['ac'] = ''; } - $this->xh[$the_parser]['ac'] .= $data; + $this->xh['ac'] .= $data; } } diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php index eb5a24c4917..481938b3400 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -234,9 +234,8 @@ public function parseRequest($data = '') $parser = xml_parser_create($this->xmlrpc_defencoding); $parser_object = new XML_RPC_Message('filler'); - $pname = (string) $parser; - $parser_object->xh[$pname] = array( + $parser_object->xh = array( 'isf' => 0, 'isf_reason' => '', 'params' => array(), @@ -265,7 +264,7 @@ public function parseRequest($data = '') xml_get_current_line_number($parser))); xml_parser_free($parser); } - elseif ($parser_object->xh[$pname]['isf']) + elseif ($parser_object->xh['isf']) { return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']); } @@ -273,17 +272,17 @@ public function parseRequest($data = '') { xml_parser_free($parser); - $m = new XML_RPC_Message($parser_object->xh[$pname]['method']); + $m = new XML_RPC_Message($parser_object->xh['method']); $plist = ''; - for ($i = 0, $c = count($parser_object->xh[$pname]['params']); $i < $c; $i++) + for ($i = 0, $c = count($parser_object->xh['params']); $i < $c; $i++) { if ($this->debug === TRUE) { - $plist .= $i.' - '.print_r(get_object_vars($parser_object->xh[$pname]['params'][$i]), TRUE).";\n"; + $plist .= $i.' - '.print_r(get_object_vars($parser_object->xh['params'][$i]), TRUE).";\n"; } - $m->addParam($parser_object->xh[$pname]['params'][$i]); + $m->addParam($parser_object->xh['params'][$i]); } if ($this->debug === TRUE) From 103c210b0c289dbb307de950008bd790f9d898b4 Mon Sep 17 00:00:00 2001 From: George Petculescu Date: Sat, 10 Feb 2024 14:54:28 +0200 Subject: [PATCH 02/14] Adds PHPUnit test for XML-RPC lib --- tests/codeigniter/libraries/Xmlrpc_test.php | 130 ++++++++++++++++++++ tests/mocks/autoloader.php | 1 + tests/mocks/libraries/xmlrpc.php | 33 +++++ tests/mocks/libraries/xmlrpcs.php | 23 ++++ 4 files changed, 187 insertions(+) create mode 100644 tests/codeigniter/libraries/Xmlrpc_test.php create mode 100644 tests/mocks/libraries/xmlrpc.php create mode 100644 tests/mocks/libraries/xmlrpcs.php diff --git a/tests/codeigniter/libraries/Xmlrpc_test.php b/tests/codeigniter/libraries/Xmlrpc_test.php new file mode 100644 index 00000000000..46d73bf6e3e --- /dev/null +++ b/tests/codeigniter/libraries/Xmlrpc_test.php @@ -0,0 +1,130 @@ +input = new CI_Input($security); + + $this->input_lib_raw_stream = new ReflectionProperty($this->input, '_raw_input_stream'); + $this->input_lib_raw_stream->setAccessible(TRUE); + + $this->ci_instance_var('input', $this->input); + $this->ci_instance_var('security', $security); + } + + // -------------------------------------------------------------------- + + public function test_xmlrpc_client() + { + $xmlrpc = new Mock_Libraries_Xmlrpc(); + $xmlrpc->server('http://rpc.test/'); + $xmlrpc->method('testcontroller.test'); + + $request = array('My Blog', 'http://www.myrpc.com/test/'); + $message = 'test'.time(); + $xml_response = $this->xml_response($message); + $xmlrpc->client->mock_response = "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\nContent-Length: ".strlen($xml_response)."\r\n\r\n$xml_response"; + + // Perform in the same request multiple calls + for ($attempt = 1; $attempt <= 2; $attempt++) + { + $xmlrpc->request($request); + + $this->assertTrue($xmlrpc->send_request()); + + $response = $xmlrpc->display_response(); + + $this->assertEquals('theuser', $response['name']); + $this->assertEquals(123435, $response['member_id']); + $this->assertEquals($message, $response['request']); + } + } + + // -------------------------------------------------------------------- + + public function test_xmlrpc_server() + { + $xmlrpcs = new Mock_Libraries_Xmlrpcs(); + + $config['functions']['Testmethod'] = array('function' => __CLASS__.'.mock_method_new_entry'); + $config['object'] = $this; + + $xmlrpcs->initialize($config); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->input_lib_raw_stream->setValue($this->input, $this->xml_request()); + + $xmlrpcs->serve(); + + $this->assertEquals('Test', $this->method_param); + } + + // -------------------------------------------------------------------- + + /** + * @param XML_RPC_Message $param + */ + public function mock_method_new_entry($param) + { + $this->method_param = $param->params[0]->scalarval(); + + return new XML_RPC_Response(new XML_RPC_Values(true, 'boolean')); + } + + // -------------------------------------------------------------------- + + private function xml_response($message) + { + return ' + + + + + + +name + +theuser + + + +member_id + +123435 + + + +request + +'.$message.' + + + + + +'; + } + + // -------------------------------------------------------------------- + + public function xml_request() + { + return ' + +Testmethod + + + +Test + + + +'; + } +} diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php index 9360a2b34bb..3e6b0b60432 100644 --- a/tests/mocks/autoloader.php +++ b/tests/mocks/autoloader.php @@ -53,6 +53,7 @@ function autoload($class) 'Upload', 'User_agent', 'Xmlrpc', + 'Xmlrpcs', 'Zip' ); diff --git a/tests/mocks/libraries/xmlrpc.php b/tests/mocks/libraries/xmlrpc.php new file mode 100644 index 00000000000..32f5f3765d5 --- /dev/null +++ b/tests/mocks/libraries/xmlrpc.php @@ -0,0 +1,33 @@ +client = new Mock_Libraries_XML_RPC_Client('/', $url, $port, $proxy, $proxy_port); + } +} + +class Mock_Libraries_XML_RPC_Client extends XML_RPC_Client { + public $mock_response = ''; + + /** + * @param XML_RPC_Message $msg + */ + public function sendPayload($msg) + { + if (empty($msg->payload)) + { + $msg->createPayload(); + } + + $fp = fopen('php://memory', 'rw+'); + fwrite($fp, $this->mock_response); + fseek($fp, 0); + + $parsed = $msg->parseResponse($fp); + fclose($fp); + + return $parsed; + } +} + diff --git a/tests/mocks/libraries/xmlrpcs.php b/tests/mocks/libraries/xmlrpcs.php new file mode 100644 index 00000000000..d93396c0189 --- /dev/null +++ b/tests/mocks/libraries/xmlrpcs.php @@ -0,0 +1,23 @@ +parseRequest(); + + $payload = 'xmlrpc_defencoding.'"?'.'>'."\n".$this->debug_msg.$r->prepare_response(); + + $this->mock_payload = "HTTP/1.1 200 OK\r\n"; + $this->mock_payload .= "Content-Type: text/xml\r\n"; + $this->mock_payload .= 'Content-Length: '.strlen($payload)."\r\n"; + + $this->mock_payload .= "\r\n"; + + $this->mock_payload .= $payload; + } +} From ec34b283305b38042614ffa5b971f6e90de209d2 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 10:08:21 +0200 Subject: [PATCH 03/14] Fix tests --- build-release.sh | 2 +- system/core/CodeIgniter.php | 2 +- tests/Bootstrap.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build-release.sh b/build-release.sh index ea549756050..47a4a5b2255 100755 --- a/build-release.sh +++ b/build-release.sh @@ -47,7 +47,7 @@ fi echo "Running tests ..." -php -d zend.enable_gc=0 -d date.timezone=UTC -d mbstring.func_overload=7 -d mbstring.internal_encoding=UTF-8 vendor/bin/phpunit --coverage-text --configuration tests/travis/sqlite.phpunit.xml +php -d zend.enable_gc=0 -d date.timezone=UTC -d mbstring.func_overload=7 vendor/bin/phpunit --coverage-text --configuration tests/travis/sqlite.phpunit.xml if [ $? -ne 0 ] then diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php index 2a61a32f7d2..f4342063eb3 100644 --- a/system/core/CodeIgniter.php +++ b/system/core/CodeIgniter.php @@ -250,7 +250,7 @@ define('MB_ENABLED', TRUE); // mbstring.internal_encoding is deprecated starting with PHP 5.6 // and it's usage triggers E_DEPRECATED messages. - @ini_set('mbstring.internal_encoding', $charset); + // @ini_set('mbstring.internal_encoding', $charset); // This is required for mb_convert_encoding() to strip invalid characters. // That's utilized by CI_Utf8, but it's also done for consistency with iconv. mb_substitute_character('none'); diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 10a21f3255d..65f75091452 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -45,7 +45,7 @@ class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper'); if (extension_loaded('mbstring')) { defined('MB_ENABLED') OR define('MB_ENABLED', TRUE); - @ini_set('mbstring.internal_encoding', 'UTF-8'); +// @ini_set('mbstring.internal_encoding', 'UTF-8'); mb_substitute_character('none'); } else From e104c9fbcaf1794a4ca38750944a14888fb9d733 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 10:14:56 +0200 Subject: [PATCH 04/14] Fix tests v2 --- system/core/CodeIgniter.php | 7 +------ tests/Bootstrap.php | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php index f4342063eb3..98f0205b1d2 100644 --- a/system/core/CodeIgniter.php +++ b/system/core/CodeIgniter.php @@ -267,18 +267,13 @@ define('ICONV_ENABLED', TRUE); // iconv.internal_encoding is deprecated starting with PHP 5.6 // and it's usage triggers E_DEPRECATED messages. - @ini_set('iconv.internal_encoding', $charset); + // @ini_set('iconv.internal_encoding', $charset); } else { define('ICONV_ENABLED', FALSE); } - if (is_php('5.6')) - { - ini_set('php.internal_encoding', $charset); - } - /* * ------------------------------------------------------ * Load compatibility features diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 65f75091452..10415fc0109 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -56,7 +56,7 @@ class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper'); if (extension_loaded('iconv')) { defined('ICONV_ENABLED') OR define('ICONV_ENABLED', TRUE); - @ini_set('iconv.internal_encoding', 'UTF-8'); + //@ini_set('iconv.internal_encoding', 'UTF-8'); } else { From 0cb0ba6cc0f760cef48cde3e2e8bed34e0c488db Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 10:18:06 +0200 Subject: [PATCH 05/14] Fix tests v3 --- .github/workflows/test-phpunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 5e54e1bc889..c2b105b1253 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -141,6 +141,6 @@ jobs: - name: PHPUnit Test run: | - php -d error_reporting=E_ALL -d zend.enable_gc=0 -d date.timezone=UTC -d mbstring.func_overload=7 -d mbstring.internal_encoding=UTF-8 vendor/bin/phpunit --coverage-text --configuration tests/travis/${{ matrix.DB }}.phpunit.xml + php -d error_reporting=E_ALL -d zend.enable_gc=0 -d date.timezone=UTC -d mbstring.func_overload=7 vendor/bin/phpunit --coverage-text --configuration tests/travis/${{ matrix.DB }}.phpunit.xml env: XDEBUG_MODE: coverage From bcf99ba89de741fe97da188a930d7c1ebbde40b2 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 10:38:22 +0200 Subject: [PATCH 06/14] Fix tests v4 --- composer.json | 2 +- tests/Bootstrap.php | 2 -- tests/travis/sqlite.phpunit.xml | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 69686efb30f..88fac21f3e6 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,6 @@ }, "require-dev": { "mikey179/vfsstream": "1.6.*", - "phpunit/phpunit": "4.* || 5.* || 9.*" + "phpunit/phpunit": "^9.5" } } diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 10415fc0109..e1a15456ee0 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -63,8 +63,6 @@ class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper'); defined('ICONV_ENABLED') OR define('ICONV_ENABLED', FALSE); } -is_php('5.6') && ini_set('php.internal_encoding', 'UTF-8'); - if (is_php('7.0')) { $test_case_code = file_get_contents(PROJECT_BASE.'vendor/phpunit/phpunit/src/Framework/TestCase.php'); diff --git a/tests/travis/sqlite.phpunit.xml b/tests/travis/sqlite.phpunit.xml index 4eaafc19fdf..f8ae65f7fd5 100644 --- a/tests/travis/sqlite.phpunit.xml +++ b/tests/travis/sqlite.phpunit.xml @@ -9,7 +9,7 @@ stopOnIncomplete="false" stopOnSkipped="false" beStrictAboutTestsThatDoNotTestAnything="false" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd" > From 1c47f7365d043747676817fb29adfe21c587c7a0 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 10:49:37 +0200 Subject: [PATCH 07/14] Fix tests v5 --- composer.json | 2 +- tests/travis/sqlite.phpunit.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 88fac21f3e6..f5badc57d8c 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,6 @@ }, "require-dev": { "mikey179/vfsstream": "1.6.*", - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^9.6" } } diff --git a/tests/travis/sqlite.phpunit.xml b/tests/travis/sqlite.phpunit.xml index f8ae65f7fd5..6d2409cfd0d 100644 --- a/tests/travis/sqlite.phpunit.xml +++ b/tests/travis/sqlite.phpunit.xml @@ -9,7 +9,7 @@ stopOnIncomplete="false" stopOnSkipped="false" beStrictAboutTestsThatDoNotTestAnything="false" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd" > From 5cff5ac7ee3bfc5c79931b7af800c72a64c6927b Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 11:17:38 +0200 Subject: [PATCH 08/14] Fix tests v6 --- tests/phpunit.xml | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/tests/phpunit.xml b/tests/phpunit.xml index a1626ce91ad..e44da492f38 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -1,25 +1,15 @@ - - - - - ./codeigniter/core - ./codeigniter/helpers - ./codeigniter/libraries - - - - - ../system/ - - + + + + ../system/ + + + + + ./codeigniter/core + ./codeigniter/helpers + ./codeigniter/libraries + + From f575dbe494ea137059c598b3438910f377d5498c Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 11:20:29 +0200 Subject: [PATCH 09/14] Fix tests v7 --- .github/workflows/test-phpunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index c2b105b1253..e94dbd40972 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -141,6 +141,6 @@ jobs: - name: PHPUnit Test run: | - php -d error_reporting=E_ALL -d zend.enable_gc=0 -d date.timezone=UTC -d mbstring.func_overload=7 vendor/bin/phpunit --coverage-text --configuration tests/travis/${{ matrix.DB }}.phpunit.xml + php -d error_reporting=E_ALL -d zend.enable_gc=0 -d date.timezone=UTC vendor/bin/phpunit --coverage-text --configuration tests/travis/${{ matrix.DB }}.phpunit.xml env: XDEBUG_MODE: coverage From aa037d0fd862ad1c01dd552f0b08cd2b54146d55 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 14:37:39 +0200 Subject: [PATCH 10/14] Fix tests v8 --- tests/codeigniter/libraries/Xmlrpc_test.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/codeigniter/libraries/Xmlrpc_test.php b/tests/codeigniter/libraries/Xmlrpc_test.php index 46d73bf6e3e..b12cbe53475 100644 --- a/tests/codeigniter/libraries/Xmlrpc_test.php +++ b/tests/codeigniter/libraries/Xmlrpc_test.php @@ -8,8 +8,11 @@ class Xmlrpc_test extends CI_TestCase { public function set_up() { - $security = new Mock_Core_Security('UTF-8'); - $this->input = new CI_Input($security); + // $security = new Mock_Core_Security('UTF-8'); + // $this->input = new CI_Input($security); + $utf8 = new Mock_Core_Utf8(); + $security = new Mock_Core_Security(); + $this->$input = new Mock_Core_Input($security, $utf8); $this->input_lib_raw_stream = new ReflectionProperty($this->input, '_raw_input_stream'); $this->input_lib_raw_stream->setAccessible(TRUE); From a578d825d5e3ac6fe145032f8535dcaee1247722 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 14:41:37 +0200 Subject: [PATCH 11/14] Fix tests v9 --- tests/codeigniter/libraries/Xmlrpc_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codeigniter/libraries/Xmlrpc_test.php b/tests/codeigniter/libraries/Xmlrpc_test.php index b12cbe53475..66b1f8e11da 100644 --- a/tests/codeigniter/libraries/Xmlrpc_test.php +++ b/tests/codeigniter/libraries/Xmlrpc_test.php @@ -12,7 +12,7 @@ public function set_up() // $this->input = new CI_Input($security); $utf8 = new Mock_Core_Utf8(); $security = new Mock_Core_Security(); - $this->$input = new Mock_Core_Input($security, $utf8); + $this->input = new Mock_Core_Input($security, $utf8); $this->input_lib_raw_stream = new ReflectionProperty($this->input, '_raw_input_stream'); $this->input_lib_raw_stream->setAccessible(TRUE); From 4368aed7b0a9b5165149a8466057af4245ec30f1 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 14:49:11 +0200 Subject: [PATCH 12/14] Add PHP 8.4 tests --- .github/workflows/test-phpunit.yml | 20 +++++++++++++++++++- composer.json | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index e94dbd40972..aaa9b17657d 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -12,10 +12,28 @@ jobs: strategy: fail-fast: false matrix: - php: [ '8.3', '8.2', '8.1', '8.0', '7.4'] + php: ['8.4', '8.3', '8.2', '8.1', '8.0', '7.4'] DB: [ 'pdo/mysql', 'pdo/pgsql', 'pdo/sqlite', 'mysqli', 'pgsql', 'sqlite' ] compiler: [ default ] include: + - php: '8.4' + DB: 'pdo/mysql' + compiler: jit + - php: '8.4' + DB: 'pdo/pgsql' + compiler: jit + - php: '8.4' + DB: 'pdo/sqlite' + compiler: jit + - php: '8.4' + DB: 'mysqli' + compiler: jit + - php: '8.4' + DB: 'pgsql' + compiler: jit + - php: '8.4' + DB: 'sqlite' + compiler: jit - php: '8.3' DB: 'pdo/mysql' compiler: jit diff --git a/composer.json b/composer.json index f5badc57d8c..ab8fb957de4 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,6 @@ }, "require-dev": { "mikey179/vfsstream": "1.6.*", - "phpunit/phpunit": "^9.6" + "phpunit/phpunit": "9.* || 10.* || 11.*" } } From cb5487171e7a883f4a0c6346ef0efb8ee7acb2bf Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 15:32:22 +0200 Subject: [PATCH 13/14] Fix PHP 8.4 deprecated warnings Github issue 6306 --- system/libraries/Xmlrpc.php | 8 ++++---- system/libraries/Xmlrpcs.php | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 12387681699..4afeaef49a5 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1162,10 +1162,10 @@ public function parseResponse($fp) 'isf_reason' => 0 ); - xml_set_object($parser, $this); - xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE); - xml_set_element_handler($parser, 'open_tag', 'closing_tag'); - xml_set_character_data_handler($parser, 'character_data'); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_set_element_handler($parser, [$this, 'open_tag'], [$this, 'closing_tag']); + xml_set_character_data_handler($parser, [$this, 'character_data']); + //xml_set_default_handler($parser, 'default_handler'); // Get headers diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php index 481938b3400..945fd495e0e 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -244,10 +244,9 @@ public function parseRequest($data = '') 'method' => '' ); - xml_set_object($parser, $parser_object); - xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE); - xml_set_element_handler($parser, 'open_tag', 'closing_tag'); - xml_set_character_data_handler($parser, 'character_data'); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_set_element_handler($parser, [$this, 'open_tag'], [$this, 'closing_tag']); + xml_set_character_data_handler($parser, [$this, 'character_data']); //xml_set_default_handler($parser, 'default_handler'); //------------------------------------- From 6a139066bcebf03026ac0b9f0f3f2b548c73aa22 Mon Sep 17 00:00:00 2001 From: Niel Buys Date: Fri, 20 Dec 2024 20:49:50 +0200 Subject: [PATCH 14/14] Fix tests v10 --- composer.json | 2 +- system/libraries/Xmlrpc.php | 19 +++++++-------- system/libraries/Xmlrpcs.php | 27 ++++++++++----------- tests/mocks/libraries/xmlrpcs.php | 39 ++++++++++++++++++++++++++----- 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index ab8fb957de4..13cb2af56f9 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "scripts": { "test:coverage": [ "@putenv XDEBUG_MODE=coverage", - "phpunit --color=always --coverage-text --configuration tests/travis/sqlite.phpunit.xml" + "phpunit --color=always --coverage-text --configuration tests/phpunit.xml" ], "post-install-cmd": [ "sed -i s/name{0}/name[0]/ vendor/mikey179/vfsstream/src/main/php/org/bovigo/vfs/vfsStream.php" diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 4afeaef49a5..9129b7210d0 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1152,20 +1152,19 @@ public function parseResponse($fp) // Create and Set Up XML Parser //------------------------------------- - $parser = xml_parser_create($this->xmlrpc_defencoding); - $this->xh = array( - 'isf' => 0, - 'ac' => '', - 'headers' => array(), - 'stack' => array(), - 'valuestack' => array(), - 'isf_reason' => 0 - ); + $parser = xml_parser_create($this->xmlrpc_defencoding); + $this->xh = array( + 'isf' => 0, + 'ac' => '', + 'headers' => array(), + 'stack' => array(), + 'valuestack' => array(), + 'isf_reason' => 0 + ); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($parser, [$this, 'open_tag'], [$this, 'closing_tag']); xml_set_character_data_handler($parser, [$this, 'character_data']); - //xml_set_default_handler($parser, 'default_handler'); // Get headers diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php index 945fd495e0e..ed28721f551 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -232,21 +232,22 @@ public function parseRequest($data = '') // Set up XML Parser //------------------------------------- - $parser = xml_parser_create($this->xmlrpc_defencoding); - $parser_object = new XML_RPC_Message('filler'); - - $parser_object->xh = array( - 'isf' => 0, - 'isf_reason' => '', - 'params' => array(), - 'stack' => array(), - 'valuestack' => array(), - 'method' => '' - ); + $parser = xml_parser_create($this->xmlrpc_defencoding); + $parser_object = new XML_RPC_Message('default_method', FALSE); + + $parser_object->xh = array( + 'isf' => 0, + 'isf_reason' => '', + 'params' => array(), + 'stack' => array(), + 'valuestack' => array(), + 'method' => '' + ); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); - xml_set_element_handler($parser, [$this, 'open_tag'], [$this, 'closing_tag']); - xml_set_character_data_handler($parser, [$this, 'character_data']); + xml_set_element_handler($parser, [$parser_object, 'open_tag'], [$parser_object, 'closing_tag']); + xml_set_character_data_handler($parser, [$parser_object, 'character_data']); + //xml_set_default_handler($parser, 'default_handler'); //------------------------------------- diff --git a/tests/mocks/libraries/xmlrpcs.php b/tests/mocks/libraries/xmlrpcs.php index d93396c0189..35f5b13090b 100644 --- a/tests/mocks/libraries/xmlrpcs.php +++ b/tests/mocks/libraries/xmlrpcs.php @@ -9,15 +9,42 @@ class Mock_Libraries_Xmlrpcs extends CI_Xmlrpcs { public function serve() { $r = $this->parseRequest(); - - $payload = 'xmlrpc_defencoding.'"?'.'>'."\n".$this->debug_msg.$r->prepare_response(); - + + if (isset($r->method_name) && isset($this->config['functions'][$r->method_name])) { + $callback = $this->config['functions'][$r->method_name]['function']; + if (is_callable($callback)) { + call_user_func($callback, $r->parameters); + } else { + throw new Exception('Invalid callback: ' . $callback); + } + } + + $payload = 'xmlrpc_defencoding . '"?>' . "\n" . + $this->debug_msg . $r->prepare_response(); + $this->mock_payload = "HTTP/1.1 200 OK\r\n"; $this->mock_payload .= "Content-Type: text/xml\r\n"; - $this->mock_payload .= 'Content-Length: '.strlen($payload)."\r\n"; - + $this->mock_payload .= 'Content-Length: ' . strlen($payload) . "\r\n"; $this->mock_payload .= "\r\n"; - $this->mock_payload .= $payload; } + + /** + * Mock XML request (example) + */ + public function xml_request() + { + // Return a mock XML request + return ' + + Testmethod + + + + Test + + + + '; + } }