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