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.

137 lines
3.9 KiB

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