$pages The pages, in order. * @return string The scan's token. */ public static function start( int $user_id, array $pages ): string { $token = strtolower( wp_generate_password( 20, false ) ); set_transient( self::key( $token ), array( 'user' => $user_id, 'pages' => array_values( $pages ), 'time' => time(), ), self::KEEP ); return $token; } /** * A scan under way (null: there is none by that token). * * @param string $token Token. * @return array{user: int, pages: array, time: int}|null */ public static function get( string $token ): ?array { if ( 1 !== preg_match( '/^[a-z0-9]{20}$/', $token ) ) { return null; } $scan = get_transient( self::key( $token ) ); if ( ! is_array( $scan ) || ! isset( $scan['user'], $scan['pages'] ) || ! is_array( $scan['pages'] ) ) { return null; } return array( 'user' => (int) $scan['user'], 'pages' => array_values( array_filter( $scan['pages'], 'is_string' ) ), 'time' => (int) ( $scan['time'] ?? 0 ), ); } /** * Keep what one request saw of one page. * * @param string $token Token. * @param int $index The page's place in the scan. * @param string $part One of PARTS. * @param array $seen What was seen. * @return void */ public static function note( string $token, int $index, string $part, array $seen ): void { $scan = self::get( $token ); if ( null !== $scan && isset( $scan['pages'][ $index ] ) && in_array( $part, self::PARTS, true ) ) { set_transient( self::key( $token, $index, $part ), $seen, self::KEEP ); } } /** * Everything the scan's requests saw, page by page. * * @param string $token Token. * @return array|null, inventory: array|null, check: array|null}> */ public static function read( string $token ): array { $scan = self::get( $token ); $pages = array(); foreach ( null === $scan ? array() : $scan['pages'] as $index => $url ) { $page = array( 'url' => $url ); foreach ( self::PARTS as $part ) { $seen = get_transient( self::key( $token, $index, $part ) ); $page[ $part ] = is_array( $seen ) ? $seen : null; } $pages[] = $page; } return $pages; } /** * Put a scan away: its notes are no longer needed. * * @param string $token Token. * @return void */ public static function end( string $token ): void { $scan = self::get( $token ); foreach ( null === $scan ? array() : array_keys( $scan['pages'] ) as $index ) { foreach ( self::PARTS as $part ) { delete_transient( self::key( $token, $index, $part ) ); } } delete_transient( self::key( $token ) ); } /** * The name a scan, or one of its notes, is kept under. * * @param string $token Token. * @param int|null $index A page's place (null: the scan itself). * @param string $part One of PARTS. * @return string */ private static function key( string $token, ?int $index = null, string $part = '' ): string { return 'wmcc_scan_' . $token . ( null === $index ? '' : '_' . $index . '_' . $part ); } }