diff --git a/README.md b/README.md index 7c62354..403908c 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ A php package to track Colissimo (La Poste) parcels ### Requirements - PHP >= 7.1 -- XML PHP Extension - Curl PHP Extension +- Json PHP Extension ### Installation ````bash @@ -26,54 +26,228 @@ try { } ```` -The result is an array of chronological status: +The result is an array of data provided by api.laposte.fr: ```` -array(5) { - [0] => - array(3) { - 'date' => - string(10) "30/05/2018" - 'label' => - string(23) "Votre colis est livré." - 'location' => - string(18) "Centre Courrier 75" - } - [1] => - array(3) { - 'date' => - string(10) "30/05/2018" - 'label' => - string(50) "Votre colis est en préparation pour la livraison." - 'location' => - string(18) "Centre Courrier 75" - } - [2] => - array(3) { - 'date' => - string(10) "30/05/2018" - 'label' => - string(52) "Votre colis est arrivé sur son site de distribution" - 'location' => - string(18) "Centre Courrier 75" - } - [3] => - array(3) { - 'date' => - string(10) "29/05/2018" - 'label' => - string(40) "Votre colis est en cours d'acheminement." - 'location' => - string(16) "Plateforme Colis" - } - [4] => - array(3) { - 'date' => - string(10) "28/05/2018" - 'label' => - string(110) "Votre colis a été déposé après l'heure limite de dépôt. Il sera expédié dès le prochain jour ouvré." - 'location' => - string(28) "Bureau de Poste Les estables" +array(4) { + ["lang"]=> + string(5) "fr_FR" + ["scope"]=> + string(8) "timeline" + ["shipment"]=> + array(13) { + ["idShip"]=> + string(13) "6H002911xxxxx" + ["notifAvailable"]=> + bool(true) + ["holder"]=> + int(4) + ["product"]=> + string(9) "colissimo" + ["isFinal"]=> + bool(true) + ["deliveryDate"]=> + string(25) "2019-04-05T14:28:00+02:00" + ["entryDate"]=> + string(25) "2019-04-04T21:22:52+02:00" + ["timeline"]=> + array(5) { + [0]=> + array(6) { + ["shortLabel"]=> + string(30) "Votre colis est pris en charge" + ["id"]=> + int(1) + ["date"]=> + string(25) "2019-04-04T21:22:52+02:00" + ["country"]=> + string(0) "" + ["status"]=> + bool(true) + ["type"]=> + int(1) + } + [1]=> + array(6) { + ["shortLabel"]=> + string(17) "Il est en chemin." + ["longLabel"]=> + string(0) "" + ["id"]=> + int(2) + ["country"]=> + string(0) "" + ["status"]=> + bool(true) + ["type"]=> + int(1) + } + [2]=> + array(5) { + ["shortLabel"]=> + string(11) "Il arrive !" + ["id"]=> + int(3) + ["country"]=> + string(0) "" + ["status"]=> + bool(true) + ["type"]=> + int(1) + } + [3]=> + array(6) { + ["shortLabel"]=> + string(51) "Votre colis vous attend dans votre point de retrait" + ["longLabel"]=> + string(0) "" + ["id"]=> + int(4) + ["country"]=> + string(0) "" + ["status"]=> + bool(true) + ["type"]=> + int(1) + } + [4]=> + array(7) { + ["shortLabel"]=> + string(27) "Votre colis a été retiré" + ["longLabel"]=> + string(0) "" + ["id"]=> + int(5) + ["date"]=> + string(25) "2019-04-05T14:28:00+02:00" + ["country"]=> + string(0) "" + ["status"]=> + bool(true) + ["type"]=> + int(1) + } + } + ["event"]=> + array(5) { + [0]=> + array(4) { + ["order"]=> + int(100) + ["status"]=> + string(6) "LIVCFM" + ["label"]=> + string(23) "Votre colis est livré." + ["date"]=> + string(25) "2019-04-05T14:28:00+02:00" + } + [1]=> + array(4) { + ["order"]=> + int(99) + ["status"]=> + string(6) "AARBPR" + ["label"]=> + string(195) "Votre colis est disponible dans votre point de retrait pendant un délai de 10 jours ouvrables. Ne tardez pas à aller le chercher ! Il vous sera remis sur présentation d'une pièce d'identité." + ["date"]=> + string(25) "2019-04-05T12:07:00+02:00" + } + [2]=> + array(4) { + ["order"]=> + int(98) + ["status"]=> + string(6) "PRELIV" + ["label"]=> + string(116) "Votre colis est dans le site de livraison qui dessert votre adresse. Nous le préparons pour le mettre en livraison." + ["date"]=> + string(25) "2019-04-05T09:27:28+02:00" + } + [3]=> + array(4) { + ["order"]=> + int(97) + ["status"]=> + string(6) "PCHTRI" + ["label"]=> + string(110) "Votre colis est en transit sur nos plateformes logistiques pour vous être livré le plus rapidement possible." + ["date"]=> + string(25) "2019-04-04T21:22:52+02:00" + } + [4]=> + array(4) { + ["order"]=> + int(96) + ["status"]=> + string(6) "PCHMQT" + ["label"]=> + string(200) "Votre Colissimo va bientôt nous être confié ! Il est en train d’être préparé chez votre expéditeur. Si vous avez des questions, vous pouvez contacter votre expéditeur ou son service clients." + ["date"]=> + string(25) "2019-04-04T16:46:30+02:00" + } + } + ["contextData"]=> + array(6) { + ["isParcelBack"]=> + bool(false) + ["removalPoint"]=> + array(4) { + ["idPoint"]=> + string(6) "319220" + ["type"]=> + string(3) "A2P" + ["name"]=> + string(19) "TOULOUSE ROQUELAINE" + ["isDiffPoint"]=> + bool(false) + } + ["deliveryChoice"]=> + array(6) { + ["deliveryChoice"]=> + int(0) + ["accola"]=> + int(0) + ["thirdParty"]=> + int(0) + ["safePlace"]=> + int(0) + ["BALCS"]=> + int(0) + ["extensionBP"]=> + int(0) + } + ["recipient"]=> + array(8) { + ["name"]=> + string(14) "M. JOHN DOE" + ["companyName"]=> + string(0) "" + ["adr2"]=> + string(23) "12 RUE DU PONT" + ["adr3"]=> + string(0) "" + ["adr4"]=> + string(0) "" + ["adr5"]=> + string(0) "" + ["zipCode"]=> + string(5) "31000" + ["city"]=> + string(8) "TOULOUSE" + } + ["originCountry"]=> + string(2) "FR" + ["arrivalCountry"]=> + string(2) "FR" + } + ["estimDate"]=> + string(25) "2019-04-05T02:00:00+02:00" + ["estimHourMin"]=> + string(25) "2019-04-08T18:00:36+02:00" + ["estimHourMax"]=> + string(25) "2019-04-08T18:00:36+02:00" } + ["returnCode"]=> + int(200) } ```` diff --git a/composer.json b/composer.json index 80bbb5c..fe516be 100644 --- a/composer.json +++ b/composer.json @@ -19,10 +19,8 @@ "require": { "php": "^7.1.0", "ext-curl": "*", - "ext-xml": "*", - "guzzlehttp/guzzle": "^6.3", - "symfony/css-selector": "^3.0", - "symfony/dom-crawler": "^3.0" + "ext-json": "*", + "guzzlehttp/guzzle": "^6.3" }, "require-dev": { "phpunit/phpunit": "^7.0" diff --git a/src/ColissimoApi.php b/src/ColissimoApi.php index 54a4454..e6a0c1e 100644 --- a/src/ColissimoApi.php +++ b/src/ColissimoApi.php @@ -2,8 +2,37 @@ namespace Hedii\ColissimoApi; +use Exception; +use GuzzleHttp\Client; +use GuzzleHttp\Cookie\SetCookie; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Exception\RequestException; + class ColissimoApi { + /** + * The http client instance. + * + * @var \GuzzleHttp\Client + */ + private $client; + + /** + * ColissimoApi constructor. + * + * @param int $connectionTimeout + * @param int $timeout + * @param bool $verify + */ + public function __construct(int $connectionTimeout = 10, int $timeout = 30, bool $verify = false) + { + $this->client = new Client([ + 'connect_timeout' => $connectionTimeout, + 'timeout' => $timeout, + 'verify' => $verify + ]); + } + /** * Get the colissimo status. * @@ -13,12 +42,51 @@ class ColissimoApi */ public function get(string $id): array { - $data = (new Parser($id))->run(); + try { + $response = $this->client->get("https://api.laposte.fr/ssu/v1/suivi-unifie/idship/{$id}", [ + 'query' => ['lang' => 'fr_FR'], + 'headers' => [ + 'Accept' => 'application/json', + 'referer' => "https://www.laposte.fr/outils/suivre-vos-envois?code={$id}", + 'Origin' => 'https://www.laposte.fr', + 'Authorization' => "Bearer {$this->getToken($id)}" + ] + ]); - if (empty($data)) { - throw new ColissimoApiException("Cannot find status for colissimo id `{$id}`"); + return json_decode($response->getBody()->getContents(), true); + } catch (ClientException $exception) { + throw new ColissimoApiException( + $exception->getResponse()->getReasonPhrase(), + $exception->getResponse()->getStatusCode() + ); + } catch (RequestException $exception) { + if ($exception->hasResponse()) { + throw new ColissimoApiException( + $exception->getResponse()->getReasonPhrase(), + $exception->getResponse()->getStatusCode() + ); + } else { + throw new ColissimoApiException( + isset($exception->getHandlerContext()['errno']) + ? curl_strerror($exception->getHandlerContext()['errno']) + : $exception->getMessage() + ); + } + } catch (Exception $exception) { + throw new ColissimoApiException($exception->getMessage(), 1, $exception); } + } + + /** + * Get the JWT token. + * + * @param string $id + * @return string + */ + private function getToken(string $id): string + { + $response = $this->client->get("https://www.laposte.fr/outils/suivre-vos-envois?code={$id}"); - return $data; + return SetCookie::fromString($response->getHeader('Set-Cookie')[0])->getValue(); } } diff --git a/src/Parser.php b/src/Parser.php deleted file mode 100644 index ed3b979..0000000 --- a/src/Parser.php +++ /dev/null @@ -1,127 +0,0 @@ -id = $id; - $this->crawler = new Crawler(); - } - - /** - * Run the parser. - * - * @return array - * @throws \Hedii\ColissimoApi\ColissimoApiException - */ - public function run(): array - { - $html = $this->getHtml($this->id); - - if (! $html) { - return []; - } - - $this->crawler->addHtmlContent($html); - - $nodeValues = $this->crawler - ->filter('table tbody tr td') - ->each(function (Crawler $node) { - return trim($node->text()); - }); - - if ($nodeValues) { - foreach (array_chunk($nodeValues, 3) as $row) { - $this->data[] = [ - 'date' => $row[0], - 'label' => $row[1], - 'location' => $row[2] - ]; - } - - return $this->data; - } - - return []; - } - - /** - * Get the html content of the colissimo url response. - * - * @param string $id - * @return null|string - * @throws \Hedii\ColissimoApi\ColissimoApiException - */ - private function getHtml(string $id): ?string - { - try { - $response = $this->client()->get("{$this->baseUrl}/{$id}"); - - return $response->getBody()->getContents() ?: null; - } catch (Exception $exception) { - throw new ColissimoApiException( - "Cannot get the colissimo url `{{$this->baseUrl}/{$id}}`. {$exception->getMessage()}. See stack trace.", - $exception->getCode(), - $exception - ); - } - } - - /** - * Get an http client instance. - * - * @return \GuzzleHttp\Client - */ - private function client(): Client - { - return new Client([ - 'connect_timeout' => 10, - 'timeout' => 30, - 'verify' => false, - 'headers' => [ - 'X-Requested-With' => 'XMLHttpRequest', - 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36', - 'Referer' => 'https://www.laposte.fr/particulier/outils/suivre-vos-envois' - ] - ]); - } -} diff --git a/tests/ColissimoApiTest.php b/tests/ColissimoApiTest.php index 0fede44..0374ee9 100644 --- a/tests/ColissimoApiTest.php +++ b/tests/ColissimoApiTest.php @@ -13,7 +13,7 @@ class ColissimoApiTest extends TestCase * * @var string */ - private $id = '8N04104266553'; + private $id = '6H00291144100'; /** * An invalid colissimo id. @@ -43,7 +43,7 @@ public function setUp(): void public function it_should_fail_on_wrong_id(): void { $this->expectException(ColissimoApiException::class); - $this->expectExceptionMessage("Cannot find status for colissimo id `{$this->invalidId}`"); + $this->expectExceptionMessage('Bad Request'); $this->colissimo->get($this->invalidId); } @@ -53,28 +53,9 @@ public function it_should_have_an_all_method(): void { $result = $this->colissimo->get($this->id); - $this->assertSame([ - [ - 'date' => '30/05/2018', - 'label' => 'Votre colis est livré.', - 'location' => 'Centre Courrier 75' - ], [ - 'date' => '30/05/2018', - 'label' => 'Votre colis est en préparation pour la livraison.', - 'location' => 'Centre Courrier 75' - ], [ - 'date' => '30/05/2018', - 'label' => 'Votre colis est arrivé sur son site de distribution', - 'location' => 'Centre Courrier 75' - ], [ - 'date' => '29/05/2018', - 'label' => 'Votre colis est en cours d\'acheminement.', - 'location' => 'Plateforme Colis' - ], [ - 'date' => '28/05/2018', - 'label' => 'Votre colis a été déposé après l\'heure limite de dépôt. Il sera expédié dès le prochain jour ouvré.', - 'location' => 'Bureau de Poste Les estables' - ] - ], $result); + $this->assertArrayHasKey('lang', $result); + $this->assertArrayHasKey('scope', $result); + $this->assertArrayHasKey('shipment', $result); + $this->assertArrayHasKey('timeline', $result['shipment']); } }