You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
3.2 KiB

  1. <?php
  2. namespace Telegraph;
  3. use ORM, Exception;
  4. use IndieWeb\MentionClient;
  5. class Webmention {
  6. private static $http = false;
  7. private static function updateStatus($webmention, $http_code, $code, $raw=null) {
  8. $status = ORM::for_table('webmention_status')->create();
  9. $status->webmention_id = $webmention->id;
  10. $status->created_at = date('Y-m-d H:i:s');
  11. if($http_code)
  12. $status->http_code = $http_code;
  13. $status->status = $code;
  14. if($raw)
  15. $status->raw_response = $raw;
  16. $status->save();
  17. // Post to the callback URL if one is set
  18. if($webmention->callback) {
  19. $payload = [
  20. 'source' => $webmention->source,
  21. 'target' => $webmention->target,
  22. 'status' => $code
  23. ];
  24. if($webmention->webmention_endpoint) {
  25. $payload['type'] = 'webmention';
  26. }
  27. if($webmention->pingback_endpoint) {
  28. $payload['type'] = 'pingback';
  29. }
  30. return self::$http->post($webmention->callback, $payload);
  31. }
  32. }
  33. public static function send($id, $client=false, $http=false) {
  34. initdb();
  35. $webmention = ORM::for_table('webmentions')->where('id', $id)->find_one();
  36. if(!$webmention) {
  37. echo 'Webmention '.$id.' was not found'."\n";
  38. return;
  39. }
  40. if(!$client)
  41. $client = new MentionClient();
  42. if(!$http)
  43. $http = new HTTP();
  44. self::$http = $http;
  45. // Discover the webmention or pingback endpoint
  46. $endpoint = $client->discoverWebmentionEndpoint($webmention->target);
  47. if(!$endpoint) {
  48. // If no webmention endpoint found, try to send a pingback
  49. $pingbackEndpoint = $client->discoverPingbackEndpoint($webmention->target);
  50. // If no pingback endpoint was found, we can't do anything else
  51. if(!$pingbackEndpoint) {
  52. return self::updateStatus($webmention, null, 'not_supported');
  53. }
  54. $webmention->pingback_endpoint = $pingbackEndpoint;
  55. $webmention->save();
  56. $success = $client->sendPingbackToEndpoint($pingbackEndpoint, $webmention->source, $webmention->target);
  57. return self::updateStatus($webmention, null, ($success ? 'accepted' : 'error'));
  58. }
  59. // There is a webmention endpoint, send the webmention now
  60. $webmention->webmention_endpoint = $endpoint;
  61. $webmention->save();
  62. $response = $client->sendWebmentionToEndpoint($endpoint, $webmention->source, $webmention->target);
  63. if(in_array($response['code'], [200,201,202])) {
  64. $status = 'accepted';
  65. $webmention->complete = $response['code'] == 200 ? 1 : 0;
  66. // Check if the endpoint returned a status URL
  67. if(array_key_exists('Location', $response['headers'])) {
  68. $webmention->webmention_status_url = \Mf2\resolveUrl($endpoint, $response['headers']['Location']);
  69. // TODO: queue a job to poll the endpoint for updates and deliver to the callback URL
  70. } else {
  71. // No status URL was returned, so we can't follow up with this later. Mark as complete.
  72. $webmention->complete = 1;
  73. }
  74. } else {
  75. $webmention->complete = 1;
  76. $status = 'error';
  77. }
  78. $webmention->save();
  79. $result = self::updateStatus($webmention, $response['code'], $status, $response['body']);
  80. $pdo = ORM::get_db();
  81. $pdo = null;
  82. return $result;
  83. }
  84. }