Skip to content

Commit

Permalink
Version 2.10.4
Browse files Browse the repository at this point in the history
  • Loading branch information
eclipxe13 committed Jun 27, 2019
2 parents 502c32c + 1cfc31e commit 74e0f6a
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 1 deletion.
7 changes: 7 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
- Remove file `ConsultaCFDIServiceSAT.svc.xml`.


## Version 2.10.4 2019-06-27

- Add `Xml::createElement` and `Xml::createElementNS` to deal with non scaped ampersand `&`
on `DOMDocument::createElement` and `DOMDocument::createElementNS`.
- Improve `Rfc::obtainDate` with invalid length dates and tests


## Version 2.10.3 2019-05-29

- Add static methods to `CfdiUtils\Utils\Xml`, this methods are created to help fixing issues found by `phpstan`:
Expand Down
11 changes: 11 additions & 0 deletions docs/TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Lista de tareas pendientes e ideas

- Compatibilidad con PHP 7.4
- Firma de CfdiUtils\Utils\Format::number el argumento $decimals debe ser entero

## Verificar problemas conocidos

### Descarga de certificados desde <https://rdc.sat.gob.mx/rccf/>
Expand All @@ -12,6 +15,14 @@ Hay que remover esta condición en cuando el sitio del SAT esté correctamente c
Buscar en el código de pruebas el uso de `CfdiUtilsTests\TestCase::newInsecurePhpDownloader(): DownloaderInterface`
y remover el método.

Al correr el siguiente comando correrá 1000 peticiones secuenciales e imprimirá el resultado, si es `0` entonces
la petición se completó, si es `60` es el error de certificado expirado.

```shell
for i in {1..1000}; do curl --verbose "https://rdc.sat.gob.mx/rccf/" > /dev/null 2>&1 ; echo $? ; done | sort | uniq -c
694 0
306 60
```

## Documentación del proyecto

Expand Down
4 changes: 4 additions & 0 deletions src/CfdiUtils/Utils/Rfc.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,15 @@ public static function obtainDate(string $rfc): int
$begin = (mb_strlen($rfc) === 12) ? 3 : 4;
// strdate is not multibyte
$strdate = strval(mb_substr($rfc, $begin, 6));
if (strlen($strdate) !== 6) {
return 0;
}
$parts = str_split($strdate, 2);
// year 2000 is leap year (%4 & %100 & %400)
/** @var int|false $date phpstan does not know that mktime can return false */
$date = mktime(0, 0, 0, (int) $parts[1], (int) $parts[2], (int) ('20' . $parts[0]));
if (false === $date) {
/** @codeCoverageIgnore it is unlikely to enter this block */
return 0;
}
if (date('ymd', $date) !== $strdate) {
Expand Down
70 changes: 69 additions & 1 deletion src/CfdiUtils/Utils/Xml.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public static function ownerDocument(DOMNode $node): DOMDocument
return $node->ownerDocument;
}

/**
* Creates a DOMDocument object version 1.0 encoding UTF-8
* with output formatting and not preserving white spaces
*
* @return DOMDocument
*/
public static function newDocument(): DOMDocument
{
$document = new DOMDocument('1.0', 'UTF-8');
Expand Down Expand Up @@ -61,6 +67,68 @@ public static function isValidXmlName(string $name): bool
. '\xC0-\xD6\xD8-\xF6\xF8-\x{2FF}\x{370}-\x{37D}\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}'
. '\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}'
. '\xB7\x{0300}-\x{036F}\x{203F}-\x{2040}]*$/u';
return 1 === preg_match($pattern, $name);
return (1 === preg_match($pattern, $name));
}

/**
* This is an alias of DOMDocument::createElement that will replace ampersand '&' with '&amp;'
* @see https://www.php.net/manual/en/domdocument.createelement.php
*
* @param DOMDocument $document
* @param string $name
* @param string $content
* @return DOMElement
*/
public static function createElement(DOMDocument $document, string $name, string $content = ''): DOMElement
{
/** @var DOMElement|false $element */
$element = null;
$previousException = null;
try {
$element = $document->createElement($name);
} catch (\Throwable $domException) {
$previousException = $domException;
}
if (! $element instanceof DOMElement) {
throw new \LogicException(sprintf('Cannot create element with name %s', $name), 0, $previousException);
}
if ('' !== $content) {
$element->appendChild($document->createTextNode($content));
}
return $element;
}

/**
* This is an alias of DOMDocument::createElementNS that will replace ampersand '&' with '&amp;'
* @see https://www.php.net/manual/en/domdocument.createelementns.php
*
* @param DOMDocument $document
* @param string $namespaceURI
* @param string $name
* @param string $content
* @return DOMElement
*/
public static function createElementNS(
DOMDocument $document,
string $namespaceURI,
string $name,
string $content = ''
): DOMElement {
/** @var DOMElement|false $element */
$element = null;
$previousException = null;
try {
$element = $document->createElementNS($namespaceURI, $name);
} catch (\Throwable $domException) {
$previousException = $domException;
}
if (! $element instanceof DOMElement) {
$message = sprintf('Cannot create element with name %s uri %s', $name, $namespaceURI);
throw new \LogicException($message, 0, $previousException);
}
if ('' !== $content) {
$element->appendChild($document->createTextNode($content));
}
return $element;
}
}
18 changes: 18 additions & 0 deletions tests/CfdiUtilsTests/Utils/RfcTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,22 @@ public function testObtainDateLeapYears()
// invalid leap year
$this->assertSame(0, Rfc::obtainDate('XXX030229XX6'));
}

/**
* @param string $rfc
* @testWith [""]
* ["ABCD010100AAA"]
* ["ABCD010001AAA"]
* ["ABCD010132AAA"]
* ["ABCD010229AAA"]
* ["ABCD000230AAA"]
* ["ABCD0A0101AAA"]
* ["ABCD010A01AAA"]
* ["ABCD01010AAAA"]
* ["ABCD-10123AAA"]
*/
public function testObtainDateWithInvalidInput(string $rfc)
{
$this->assertSame(0, Rfc::obtainDate($rfc));
}
}
102 changes: 102 additions & 0 deletions tests/CfdiUtilsTests/Utils/XmlTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php
namespace CfdiUtilsTests\Utils;

use CfdiUtils\Utils\Xml;
use CfdiUtilsTests\TestCase;
use DOMDocument;

class XmlTest extends TestCase
{
public function testMethodDocumentElementWithoutRootElement()
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessage('DOM Document does not have root element');
Xml::documentElement(new DOMDocument());
}

public function testMethodDocumentElementWithRootElement()
{
$document = new DOMDocument();
$root = $document->createElement('root');
$document->appendChild($root);
$this->assertSame($root, Xml::documentElement($document));
}

/**
* @param string $expected
* @param string $content
* @testWith ["", ""]
* ["foo", "foo"]
* ["&amp;", "&"]
* ["&lt;", "<"]
* ["&gt;", ">"]
* ["'", "'"]
* ["\"", "\""]
* ["&amp;copy;", "&copy;"]
* ["foo &amp; bar", "foo & bar"]
*/
public function testMethodCreateElement(string $expected, string $content)
{
$elementName = 'element';
$document = Xml::newDocument();
$element = Xml::createElement($document, $elementName, $content);
$document->appendChild($element);
$this->assertSame($content, $element->textContent);
$this->assertXmlStringEqualsXmlString(
sprintf('<%1$s>%2$s</%1$s>', $elementName, $expected),
$document->saveXML($element)
);
}

public function testMethodCreateElementWithBadName()
{
$document = Xml::newDocument();
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Cannot create element');
Xml::createElement($document, '');
}

/**
* @param string $expected
* @param string $content
* @testWith ["", ""]
* ["foo", "foo"]
* ["&amp;", "&"]
* ["&lt;", "<"]
* ["&gt;", ">"]
* ["'", "'"]
* ["\"", "\""]
* ["&amp;copy;", "&copy;"]
* ["foo &amp; bar", "foo & bar"]
*/
public function testMethodCreateElementNs(string $expected, string $content)
{
$prefix = 'foo';
$namespaceURI = 'http://tempuri.org/';
$elementName = $prefix . ':element';
$document = Xml::newDocument();
$element = Xml::createElementNS($document, $namespaceURI, $elementName, $content);
$document->appendChild($element);
$this->assertSame($content, $element->textContent);
$this->assertXmlStringEqualsXmlString(
sprintf('<%1$s xmlns:%3$s="%4$s">%2$s</%1$s>', $elementName, $expected, $prefix, $namespaceURI),
$document->saveXML($element)
);
}

public function testMethodCreateElementNsWithBadName()
{
$document = Xml::newDocument();
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Cannot create element');
Xml::createElementNS($document, 'http://tempuri.org/', '');
}

public function testMethodCreateElementNsWithBadUri()
{
$document = Xml::newDocument();
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Cannot create element');
Xml::createElementNS($document, '', 'x:foo');
}
}

0 comments on commit 74e0f6a

Please sign in to comment.