Initial commit, start creating a webmention sender
This commit is contained in:
commit
4eba80387d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/vendor/
|
23
composer.json
Normal file
23
composer.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "lewisdale/webmentions",
|
||||||
|
"type": "project",
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^10.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Lewisdale\\Webmentions\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Lewis Dale",
|
||||||
|
"email": "lewis@ihd.software"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"symfony/dom-crawler": "^6.2",
|
||||||
|
"symfony/css-selector": "^6.2",
|
||||||
|
"symfony/http-client": "^6.2"
|
||||||
|
}
|
||||||
|
}
|
2412
composer.lock
generated
Normal file
2412
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
index.php
Normal file
11
index.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . "/vendor/autoload.php";
|
||||||
|
|
||||||
|
use Lewisdale\Webmentions\Webmention;
|
||||||
|
|
||||||
|
$mentioner = new Webmention();
|
||||||
|
|
||||||
|
$mentioner->sendForPage("https://lewisdale.dev/post/bringing-my-omg-lol-now-page-into-eleventy/");
|
||||||
|
|
||||||
|
?>
|
31
src/EndpointParser.php
Normal file
31
src/EndpointParser.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Lewisdale\Webmentions;
|
||||||
|
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
|
class EndpointParser {
|
||||||
|
public static function parse(ResponseInterface $response) : string | null
|
||||||
|
{
|
||||||
|
$headers = $response->getHeaders();
|
||||||
|
$endpoint = null;
|
||||||
|
|
||||||
|
if (isset($headers["link"])) {
|
||||||
|
$link = $headers["link"][0];
|
||||||
|
if (preg_match('/rel=("?)webmention("?)/', $link)) {
|
||||||
|
$matches = [];
|
||||||
|
preg_match('/\<(..*?)\>/', $link, $matches);
|
||||||
|
|
||||||
|
if (count($matches) > 1) {
|
||||||
|
$endpoint = $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($endpoint && !str_contains($endpoint, "https://")) {
|
||||||
|
$res = parse_url($response->getInfo('url'));
|
||||||
|
$endpoint = $res["scheme"] . "://" . $res["host"] . $endpoint;
|
||||||
|
}
|
||||||
|
return $endpoint;
|
||||||
|
}
|
||||||
|
}
|
72
src/Webmention.php
Normal file
72
src/Webmention.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lewisdale\Webmentions;
|
||||||
|
|
||||||
|
use DOMDocument;
|
||||||
|
use Symfony\Component\DomCrawler\Crawler;
|
||||||
|
use Symfony\Component\HttpClient\HttpClient;
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
|
class Webmention {
|
||||||
|
private readonly HttpClientInterface $client;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->client = HttpClient::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendForPage(string $source) : void {
|
||||||
|
// $urls = $this->getUrls($source);
|
||||||
|
|
||||||
|
// foreach($urls as $target) {
|
||||||
|
// $this->sendWebmention($source, $target);
|
||||||
|
// }
|
||||||
|
|
||||||
|
$this->sendWebmention($source, "https://webmention.rocks/test/1");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUrls(string $url) : array {
|
||||||
|
$page = file_get_contents($url);
|
||||||
|
$doc = new Crawler($page);
|
||||||
|
|
||||||
|
$urls = [];
|
||||||
|
foreach ($doc->filter('.h-entry a') as $anchor) {
|
||||||
|
$target_url = $anchor->attributes->getNamedItem('href')->textContent;
|
||||||
|
|
||||||
|
if ($target_url !== null && strlen($target_url)) {
|
||||||
|
$urls[] = $target_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendWebmention(string $source, string $target) {
|
||||||
|
// 1. Endpoint discovery
|
||||||
|
// 1.1 Parse page
|
||||||
|
// 1.2 Look for rel="webmention"
|
||||||
|
$endpoint = $this->getWebmentionEndpoint($target);
|
||||||
|
echo ($endpoint ?? "no :(") . "<br />";
|
||||||
|
// 2. Send webmention to endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getWebmentionEndpoint(string $url) : string | null {
|
||||||
|
$response = $this->client->request('GET', $url);
|
||||||
|
// echo "<pre>";
|
||||||
|
// var_dump($response->getInfo());
|
||||||
|
// echo "</pre>";
|
||||||
|
|
||||||
|
return EndpointParser::parse($response);
|
||||||
|
|
||||||
|
// $doc = new Crawler($page);
|
||||||
|
|
||||||
|
// $links = $doc->filter('link[rel="webmention"]');
|
||||||
|
|
||||||
|
// if ($links->count()) {
|
||||||
|
// return $links->first()->attr('href');
|
||||||
|
// } else {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
38
tests/EndpointParserTest.php
Normal file
38
tests/EndpointParserTest.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
use Lewisdale\Webmentions\EndpointParser;
|
||||||
|
|
||||||
|
|
||||||
|
class EndpointParserTest extends TestCase {
|
||||||
|
public function testParsesRelativeEndpointFromResponseHeaders() {
|
||||||
|
$response = $this->createStub(ResponseInterface::class);
|
||||||
|
|
||||||
|
$response->method('getHeaders')
|
||||||
|
->willReturn([
|
||||||
|
"link" => ["</test/1/webmention>; rel=webmention"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->method('getInfo')
|
||||||
|
->willReturn('https://webmention.rocks/test/1');
|
||||||
|
|
||||||
|
$this->assertSame("https://webmention.rocks/test/1/webmention", EndpointParser::parse($response));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParsesRelativeEndpointWithQuotedRelInResponseHeader() {
|
||||||
|
$response = $this->createStub(ResponseInterface::class);
|
||||||
|
|
||||||
|
$response->method('getHeaders')
|
||||||
|
->willReturn([
|
||||||
|
"link" => ['</test/5/webmention>; rel="webmention"'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$response->method('getInfo')
|
||||||
|
->willReturn('https://webmention.rocks/test/5');
|
||||||
|
|
||||||
|
$this->assertSame("https://webmention.rocks/test/5/webmention", EndpointParser::parse($response));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user