From 243c6304ce6e1f4584cbb2677c444c63b5408ac9 Mon Sep 17 00:00:00 2001 From: Edouard Courty Date: Fri, 14 Mar 2025 18:44:43 +0100 Subject: [PATCH 1/3] feat(cid): add CID encoder --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 2 +- composer.json | 3 ++- src/Service/CIDEncoder.php | 31 +++++++++++++++++++++++++++++++ tests/Service/CIDEncoderTest.php | 24 ++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) delete mode 100644 .DS_Store create mode 100644 src/Service/CIDEncoder.php create mode 100644 tests/Service/CIDEncoderTest.php diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index dbb5eaf7a8157ae80b3a6acff198ae060c24d12f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%TB{E5FFD25zmSf7o_|EmH2~Ds8A&y5`{a^@(u}V0l_VI{()cM`#8a@ZI#3Y zaYG30O6zf)o!xqp*fjvty6>+64FC~cus*})3zPfeV>aPO=84AU$T7qz2591HELsOt z0af6yDInkOJbK7+gIl(r-|vuDStreVCux4dC|M%b>CJa*?0wBl$?M@dV7>;-MQmUX zyEwo;I%wgLy$-LpxOUv2UuBz>fW3sit72E1)!_Fx@x&ZykmEVX5s~|dV>|DZ{b3OQ z_EY>rcaWudcFs7iewfBKXRv`bXVFEwnhi4lmy&W3c3AtGb2mxWpUwq+ zh&%E!s+5sC_JpibWnPVp0eaQ!MzknLMa)VC*fw3AAYQa6$4`#p1Jz`nW}!6CDLgQ9 zW}nxfnpNJWN-T@0{h|W$*3zO`huW$Fs(>mmQb5*+m@b%jEF9XUgN;1`5bGSa#=iVf z5Kind@mM(I9hz}eqN5sr#4wJ|@z}>D9t($#4&x6W##c7}gko%U=8tVSOyW>mRX`P} zDo}Hm4cY(O-=F`hB)w7vRDpk`fT?eGH(Q*N-&@BfCwpy7Kcb6CT;b4C*!b<(c4RAF crd#8^SUSYSW8sh^H2ouBWza?y_*Dfy0G^b&MF0Q* diff --git a/.gitignore b/.gitignore index 61942b9..10089d8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ vendor examples/archive.tar -test.php +*.php composer.lock .DS_Store \ No newline at end of file diff --git a/composer.json b/composer.json index ba08aa7..e99f81d 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "type": "library", "require": { "php": ">= 8.3", - "symfony/http-client": "^7.2" + "symfony/http-client": "^7.2", + "selective/base32": "^2.0" }, "require-dev": { "phpunit/phpunit": "^12.0", diff --git a/src/Service/CIDEncoder.php b/src/Service/CIDEncoder.php new file mode 100644 index 0000000..de016e4 --- /dev/null +++ b/src/Service/CIDEncoder.php @@ -0,0 +1,31 @@ +encode($cidBinary, false); + return 'b' . mb_strtolower($cidBase32); + } + + /** + * Compute the multihash using SHA-256. + */ + private static function computeMultihash(string $data): string + { + $hash = hash('sha256', $data, true); + + return pack("C*", 0x12, 0x20) . $hash; + } +} diff --git a/tests/Service/CIDEncoderTest.php b/tests/Service/CIDEncoderTest.php new file mode 100644 index 0000000..7890b01 --- /dev/null +++ b/tests/Service/CIDEncoderTest.php @@ -0,0 +1,24 @@ +assertSame($expectedCIDv1, $computedCIDv1); + } +} From 50b94efcc5d70496dd1094d37df36cc62d232493 Mon Sep 17 00:00:00 2001 From: Edouard Courty Date: Sat, 15 Mar 2025 13:20:33 +0100 Subject: [PATCH 2/3] fix(tests): fix ping test --- tests/Client/IPFSClientTest.php | 5 ++++- tests/Service/CIDEncoderTest.php | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/Client/IPFSClientTest.php b/tests/Client/IPFSClientTest.php index 85a3c7d..9354604 100644 --- a/tests/Client/IPFSClientTest.php +++ b/tests/Client/IPFSClientTest.php @@ -265,6 +265,9 @@ public function testPing(): void 'Time' => '1234567890', 'Text' => 'Hello, World!', ]; + $jsonEncoded = json_encode($mockReturn); + // Ping responses contain multiple JSON objects separated by newlines. + $actualMockReturn = implode("\n", [$jsonEncoded, $jsonEncoded, $jsonEncoded]); $this->httpClient ->expects($this->once()) @@ -275,7 +278,7 @@ public function testPing(): void 'count' => 10, ], ]) - ->willReturn(json_encode($mockReturn)); + ->willReturn($actualMockReturn); $result = $this->client->ping('QmZ4tDuvese8GKQ3vz8Fq8bKz1q3z1z1z1z1z1z1z1z1z'); diff --git a/tests/Service/CIDEncoderTest.php b/tests/Service/CIDEncoderTest.php index 7890b01..ee6762b 100644 --- a/tests/Service/CIDEncoderTest.php +++ b/tests/Service/CIDEncoderTest.php @@ -12,6 +12,10 @@ */ class CIDEncoderTest extends TestCase { + /** + * @covers ::computeCIDv1 + * @covers ::computeMultihash + */ public function testItEncodes(): void { $data = 'Hello, world!'; From a538546112ca5fc156cbdd89e29ab54d01f17395 Mon Sep 17 00:00:00 2001 From: Edouard Courty Date: Sat, 15 Mar 2025 13:37:15 +0100 Subject: [PATCH 3/3] docs(project): add changelog --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++ README.md | 3 ++- src/Client/IPFSClient.php | 13 +++++++++++- tests/Client/IPFSClientTest.php | 1 - 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8711839 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ +# IPFS-PHP Changelog + +This file contains information about every addition, update and deletion in the IPFS-PHP library. +It is recommended to read this file before updating the library to a new version. + +## v1.0.0 + +Initial release of the project. + +#### Additions + +- Added the `IPFS\Client\IPFSClient` class to interact with IPFS nodes + - Supports the following IPFS methods: + - `add` + - `cat` + - `get` + - `ls` + - `pin/add` + - `pin/rm` + - `version` + - `ping` + - Added the corresponding response models and transformers +- Added unit tests + +## v1.1.0 + +This releases brings support for the `CID` IPFS identifiers. + +#### Additions + +- Added the `IPFS\Service\CIDEncoder` class that allows for encoding v1 CIDs in the `bafk` format. + +#### Updates + +- Enhanced the `IPFSClient::ping` unit test to handle the actual response format from IPFS nodes. diff --git a/README.md b/README.md index 3478571..c83e975 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ [![PHP CI](https://github.com/EdouardCourty/ipfs-php/actions/workflows/php_ci.yml/badge.svg)](https://github.com/EdouardCourty/ipfs-php/actions/workflows/php_ci.yml) -IPFS-PHP provides a simple way to interact with an IPFS Node using PHP. +IPFS-PHP provides a simple way to interact with an IPFS Node using PHP. +The changelog for this project can be found [here](./CHANGELOG.md). ## Installation diff --git a/src/Client/IPFSClient.php b/src/Client/IPFSClient.php index 81151e4..c3322f0 100644 --- a/src/Client/IPFSClient.php +++ b/src/Client/IPFSClient.php @@ -4,6 +4,7 @@ namespace IPFS\Client; +use IPFS\Exception\IPFSTransportException; use IPFS\Model\File; use IPFS\Model\Node; use IPFS\Model\Ping; @@ -147,7 +148,17 @@ public function ping(string $nodeId, int $count = 10): Ping ], ]); - $parsedResponse = json_decode($response, true); + $parts = explode("\n", $response); + $filtered = array_filter($parts, function (string $value) { + return mb_strlen(trim($value)) > 0; + }); + + if (empty($filtered) === true) { + throw new IPFSTransportException('Unable to decode ping response.'); + } + + $realResponse = (string) $filtered[\count($filtered) - 1]; + $parsedResponse = json_decode($realResponse, true); $pingTransformer = new PingTransformer(); return $pingTransformer->transform($parsedResponse); diff --git a/tests/Client/IPFSClientTest.php b/tests/Client/IPFSClientTest.php index 9354604..58b3b5d 100644 --- a/tests/Client/IPFSClientTest.php +++ b/tests/Client/IPFSClientTest.php @@ -268,7 +268,6 @@ public function testPing(): void $jsonEncoded = json_encode($mockReturn); // Ping responses contain multiple JSON objects separated by newlines. $actualMockReturn = implode("\n", [$jsonEncoded, $jsonEncoded, $jsonEncoded]); - $this->httpClient ->expects($this->once()) ->method('request')