PluginProbe
ActivityPub / 8.0.2
ActivityPub v8.0.2
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / class-tombstone.php

class-tombstone.php in ActivityPub 8.0.2, at includes/class-tombstone.php

251 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Tombstone class file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub;
9
10 use Activitypub\Activity\Base_Object;
11
12 /**
13 * ActivityPub Tombstone Class.
14 *
15 * Handles detection and management of tombstoned (deleted) ActivityPub resources.
16 * A tombstone in ActivityPub represents a deleted object that was previously available.
17 * This class provides methods to detect tombstones across various data formats including
18 * URLs, ActivityPub objects, arrays, and WordPress error responses.
19 *
20 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone
21 */
22 class Tombstone {
23 /**
24 * HTTP status codes that indicate a tombstoned resource.
25 *
26 * - 404: Not Found - Resource no longer exists
27 * - 410: Gone - Resource was intentionally removed
28 *
29 * @var int[] Array of HTTP status codes indicating tombstones.
30 */
31 private static $codes = array( 404, 410 );
32
33 /**
34 * Check if a tombstone exists for the given resource.
35 *
36 * This is the main entry point for tombstone detection. It accepts various
37 * data types and routes them to the appropriate checking method:
38 * - URLs (string): Checks remote or local tombstone status
39 * - WP_Error objects: Checks for tombstone-indicating HTTP status codes
40 * - Arrays: Checks for ActivityPub Tombstone type
41 * - Objects: Checks for ActivityPub Tombstone type or Base_Object instances
42 *
43 * @param string|\WP_Error|array|object $various The resource data to check for tombstone status.
44 * Can be a URL, error object, ActivityPub array, or object.
45 *
46 * @return bool True if the resource is tombstoned, false otherwise.
47 */
48 public static function exists( $various ) {
49 if ( \is_wp_error( $various ) ) {
50 return self::exists_in_error( $various );
51 }
52
53 if ( \is_string( $various ) ) {
54 if ( is_same_domain( $various ) ) {
55 return self::exists_local( $various );
56 }
57 return self::exists_remote( $various );
58 }
59
60 if ( \is_array( $various ) ) {
61 return self::check_array( $various );
62 }
63
64 if ( \is_object( $various ) ) {
65 return self::check_object( $various );
66 }
67
68 return false;
69 }
70
71 /**
72 * Check if a remote URL is tombstoned.
73 *
74 * Makes an HTTP request to the remote URL with ActivityPub headers
75 * and checks for tombstone indicators:
76 * - HTTP 404/410 status codes
77 * - ActivityPub Tombstone object type in response body
78 *
79 * @param string $url The remote URL to check for tombstone status.
80 *
81 * @return bool True if the remote URL is tombstoned, false otherwise.
82 */
83 public static function exists_remote( $url ) {
84 /**
85 * Fires before checking if the URL is a tombstone.
86 *
87 * @param string $url The URL to check.
88 */
89 \do_action( 'activitypub_pre_http_is_tombstone', $url );
90
91 $response = Http::get( $url );
92
93 if ( ! \is_wp_error( $response ) ) {
94 $data = \wp_remote_retrieve_body( $response );
95 $data = \json_decode( $data, true );
96
97 return self::check_array( $data );
98 }
99
100 if ( in_array( (int) $response->get_error_code(), self::$codes, true ) ) {
101 return true;
102 }
103
104 return false;
105 }
106
107 /**
108 * Check if a local URL is tombstoned.
109 *
110 * Checks against the local tombstone URL registry stored in WordPress options.
111 * Local URLs are normalized before comparison to ensure consistent matching.
112 *
113 * @param string $url The local URL to check for tombstone status.
114 *
115 * @return bool True if the local URL is in the tombstone registry, false otherwise.
116 */
117 public static function exists_local( $url ) {
118 $urls = get_option( 'activitypub_tombstone_urls', array() );
119
120 return in_array( normalize_url( $url ), $urls, true );
121 }
122
123 /**
124 * Check if a WP_Error object indicates a tombstoned resource.
125 *
126 * Examines the error data for HTTP status codes that indicate tombstones.
127 * This is typically used when HTTP requests return error responses.
128 *
129 * @param \WP_Error $wp_error The WordPress error object to examine.
130 *
131 * @return bool True if the error indicates a tombstoned resource, false otherwise.
132 */
133 public static function exists_in_error( $wp_error ) {
134 if ( ! \is_wp_error( $wp_error ) ) {
135 return false;
136 }
137
138 $data = $wp_error->get_error_data();
139 if ( isset( $data['status'] ) && in_array( (int) $data['status'], self::$codes, true ) ) {
140 return true;
141 }
142
143 return false;
144 }
145
146 /**
147 * Check if an array represents an ActivityPub Tombstone object.
148 *
149 * Examines the array for the ActivityPub 'type' property set to 'Tombstone'.
150 * This follows the ActivityStreams specification for tombstone objects.
151 *
152 * @param array|mixed $data The array data to check. Non-arrays return false.
153 *
154 * @return bool True if the array represents a Tombstone object, false otherwise.
155 */
156 private static function check_array( $data ) {
157 if ( ! \is_array( $data ) ) {
158 return false;
159 }
160
161 if ( isset( $data['type'] ) && 'Tombstone' === $data['type'] ) {
162 return true;
163 }
164
165 return false;
166 }
167
168 /**
169 * Check if an object represents an ActivityPub Tombstone.
170 *
171 * Checks for tombstone indicators in objects:
172 * - Standard objects: 'type' property set to 'Tombstone'
173 * - Base_Object instances: Uses get_type() method to check for 'Tombstone'
174 *
175 * @param object|mixed $data The object data to check. Non-objects return false.
176 *
177 * @return bool True if the object represents a Tombstone, false otherwise.
178 */
179 private static function check_object( $data ) {
180 if ( ! \is_object( $data ) ) {
181 return false;
182 }
183
184 if ( isset( $data->type ) && 'Tombstone' === $data->type ) {
185 return true;
186 }
187
188 if ( $data instanceof Base_Object && 'Tombstone' === $data->get_type() ) {
189 return true;
190 }
191
192 return false;
193 }
194
195 /**
196 * Add one or more URLs to the local tombstone registry.
197 *
198 * "Buries" URLs by adding them to the local tombstone URL registry.
199 * URLs are normalized before storage and duplicates are automatically removed.
200 * This marks the URLs as tombstoned for future local checks.
201 *
202 * @param string ...$urls The URLs to add to the tombstone registry.
203 */
204 public static function bury( ...$urls ) {
205 $to_add = array();
206
207 foreach ( $urls as $url ) {
208 if ( \filter_var( $url, \FILTER_VALIDATE_URL ) ) {
209 $to_add[] = normalize_url( $url );
210 }
211 }
212
213 if ( empty( $to_add ) ) {
214 return;
215 }
216
217 $stored_urls = \get_option( 'activitypub_tombstone_urls', array() );
218 $stored_urls = \array_merge( $stored_urls, $to_add );
219 $stored_urls = \array_unique( $stored_urls );
220
221 \update_option( 'activitypub_tombstone_urls', $stored_urls );
222 }
223
224 /**
225 * Remove one or more URLs from the local tombstone registry.
226 *
227 * Removes URLs from the local tombstone URL registry.
228 * URLs are normalized before comparison to ensure consistent matching.
229 * This marks the URLs as no longer tombstoned for future local checks.
230 *
231 * @param string ...$urls The URLs to remove from the tombstone registry.
232 */
233 public static function remove( ...$urls ) {
234 $to_remove = array();
235
236 foreach ( $urls as $url ) {
237 if ( \filter_var( $url, \FILTER_VALIDATE_URL ) ) {
238 $to_remove[] = normalize_url( $url );
239 }
240 }
241
242 if ( empty( $to_remove ) ) {
243 return;
244 }
245
246 $stored_urls = \get_option( 'activitypub_tombstone_urls', array() );
247 $stored_urls = \array_diff( $stored_urls, $to_remove );
248 \update_option( 'activitypub_tombstone_urls', $stored_urls );
249 }
250 }
251