prefix . 'ariconsent_snapshots'; } /** * What the visitor sees right now, in the current language. * * @return array */ public static function content() { $settings = Settings::get(); $categories = array(); foreach ( Services::categories() as $slug => $category ) { $categories[ $slug ] = array( 'label' => $category['label'], 'description' => $category['description'], 'required' => ! empty( $category['required'] ), ); } $services = array(); foreach ( Services::listed() as $id => $service ) { $services[ $id ] = array( 'name' => $service['name'], 'provider' => $service['provider'], 'category' => $service['category'], ); } ksort( $services ); $policy = Multilingual::privacy_url( $settings ); return array( 'locale' => determine_locale(), 'revision' => (int) $settings['revision'], 'texts' => Settings::texts(), 'categories' => $categories, 'services' => $services, 'policy_url' => $policy ? (string) $policy : '', ); } /** * Hash of the current banner, stored if it is new. * * @return string 64-character hex hash. */ public static function current() { $content = self::content(); $hash = hash( 'sha256', (string) wp_json_encode( $content ) ); self::store( $hash, $content ); return $hash; } /** * Stores a snapshot once. Known hashes are cached in an option so normal page views do no writes. * * @param string $hash Hash. * @param array $content Content. */ public static function store( $hash, array $content ) { $known = (array) get_option( self::KNOWN_OPT, array() ); if ( in_array( $hash, $known, true ) ) { return; } global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom table; INSERT IGNORE keeps one row per hash. $wpdb->query( $wpdb->prepare( 'INSERT IGNORE INTO %i (hash, created_at, content) VALUES (%s, %s, %s)', $table, $hash, current_time( 'mysql', true ), wp_json_encode( $content ) ) ); if ( self::exists( $hash ) ) { $known[] = $hash; update_option( self::KNOWN_OPT, array_slice( array_values( array_unique( $known ) ), -200 ), false ); } } /** * Whether a snapshot exists. * * @param string $hash Hash. * @return bool */ public static function exists( $hash ) { return null !== self::get( $hash ); } /** * Loads a snapshot. * * @param string $hash Hash. * @return array{hash: string, created_at: string, content: array}|null */ public static function get( $hash ) { if ( ! is_string( $hash ) || ! preg_match( '/^[a-f0-9]{64}$/', $hash ) ) { return null; } global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom table. $row = $wpdb->get_row( $wpdb->prepare( 'SELECT hash, created_at, content FROM %i WHERE hash = %s', $table, $hash ), ARRAY_A ); if ( ! $row ) { return null; } $content = json_decode( (string) $row['content'], true ); return array( 'hash' => (string) $row['hash'], 'created_at' => (string) $row['created_at'], 'content' => is_array( $content ) ? $content : array(), ); } }