@@ -403,55 +403,86 @@ public function testRaw2JsonWithContext()
403403 */
404404 public function testXML2Array ()
405405 {
406- // Ensure an XML file at risk of entity expansion can be avoided safely
406+
407407 $ inputXML = <<<XML
408408<?xml version="1.0"?>
409- <!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING">]>
409+ <!DOCTYPE results [
410+ <!ENTITY long "SOME_SUPER_LONG_STRING">
411+ ]>
410412<results>
411- <result>Now include &long; lots of times to expand the in-memory size of this XML structure </result>
412- <result>&long;&long;&long; </result>
413+ <result>My para </result>
414+ <result>Ampersand & is retained and not double encoded </result>
413415</results>
414416XML
415- ;
416- try {
417- Convert::xml2array ($ inputXML , true );
418- } catch (Exception $ ex ) {
419- }
420- $ this ->assertTrue (
421- isset ($ ex )
422- && $ ex instanceof InvalidArgumentException
423- && $ ex ->getMessage () === 'XML Doctype parsing disabled '
424- );
425-
426- // Test without doctype validation
417+ ;
427418 $ expected = [
428- 'result ' => [
429- 'Now include SOME_SUPER_LONG_STRING lots of times to expand the in-memory size of this XML structure ' ,
430- [
431- 'long ' => [
432- [
433- 'long ' => 'SOME_SUPER_LONG_STRING '
434- ],
435- [
436- 'long ' => 'SOME_SUPER_LONG_STRING '
437- ],
438- [
439- 'long ' => 'SOME_SUPER_LONG_STRING '
440- ]
441- ]
442- ]
443- ]
419+ 'result ' => [
420+ 'My para ' ,
421+ 'Ampersand & is retained and not double encoded '
422+ ]
444423 ];
445- $ result = Convert::xml2array ($ inputXML , false , true );
446- $ this ->assertEquals (
447- $ expected ,
448- $ result
449- );
450- $ result = Convert::xml2array ($ inputXML , false , false );
451- $ this ->assertEquals (
452- $ expected ,
453- $ result
454- );
424+ $ actual = Convert::xml2array ($ inputXML , false );
425+ $ this ->assertEquals ($ expected , $ actual );
426+ $ this ->expectException (InvalidArgumentException::class);
427+ $ this ->expectExceptionMessage ('XML Doctype parsing disabled ' );
428+ Convert::xml2array ($ inputXML , true );
429+ }
430+
431+ /**
432+ * Tests {@link Convert::xml2array()} if an exception the contains a reference to a removed <!ENTITY />
433+ */
434+ public function testXML2ArrayEntityException ()
435+ {
436+ $ inputXML = <<<XML
437+ <?xml version="1.0"?>
438+ <!DOCTYPE results [
439+ <!ENTITY long "SOME_SUPER_LONG_STRING">
440+ ]>
441+ <results>
442+ <result>Now include &long; lots of times to expand the in-memory size of this XML structure</result>
443+ <result>&long;&long;&long;</result>
444+ </results>
445+ XML ;
446+ $ this ->expectException (Exception::class);
447+ $ this ->expectExceptionMessage ('String could not be parsed as XML ' );
448+ Convert::xml2array ($ inputXML );
449+ }
450+
451+ /**
452+ * Tests {@link Convert::xml2array()} if an exception the contains a reference to a multiple removed <!ENTITY />
453+ */
454+ public function testXML2ArrayMultipleEntitiesException ()
455+ {
456+ $ inputXML = <<<XML
457+ <?xml version="1.0"?>
458+ <!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING"><!ENTITY short "SHORT_STRING">]>
459+ <results>
460+ <result>Now include &long; and &short; lots of times</result>
461+ <result>&long;&long;&long;&short;&short;&short;</result>
462+ </results>
463+ XML ;
464+ $ this ->expectException (Exception::class);
465+ $ this ->expectExceptionMessage ('String could not be parsed as XML ' );
466+ Convert::xml2array ($ inputXML );
467+ }
468+
469+ /**
470+ * Tests {@link Convert::xml2array()} if there is a malicious <!ENTITY /> present
471+ */
472+ public function testXML2ArrayMaliciousEntityException ()
473+ {
474+ $ inputXML = <<<XML
475+ <?xml version="1.0"?>
476+ <!DOCTYPE results [
477+ <!ENTITY><!<!ENTITY>ENTITY ext SYSTEM "http://evil.com">
478+ ]>
479+ <results>
480+ <result>Evil document</result>
481+ </results>
482+ XML ;
483+ $ this ->expectException (InvalidArgumentException::class);
484+ $ this ->expectExceptionMessage ('Malicious XML entity detected ' );
485+ Convert::xml2array ($ inputXML );
455486 }
456487
457488 /**
0 commit comments