query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, %s, 'no')", $name, (string) $now ) ); return 0 !== $inserted; } /** * Forget every claim. Used on uninstall. * * @return void */ public static function purge() { self::sweep( PHP_INT_MAX ); } /** * What makes two envelopes the same lead: the form and everything the * visitor typed. The submission id is left out, being the part that differs. * * Keyed with the plugin's secret so the option name says nothing about the * person who filled the form in. * * @param array $envelope The envelope. * @return string */ public static function fingerprint( array $envelope ) { $parts = array( 'form' => isset( $envelope['form']['key'] ) ? (string) $envelope['form']['key'] : '', 'lead' => isset( $envelope['lead'] ) ? $envelope['lead'] : array(), 'data' => isset( $envelope['data'] ) ? $envelope['data'] : array(), ); return substr( hash_hmac( 'sha256', (string) wp_json_encode( $parts ), Send4_Submission_Id::secret() ), 0, 40 ); } /** * Seconds during which an identical envelope counts as a repeat. * * @param array $envelope The envelope. * @return int */ private static function window( array $envelope ) { /** * Filter the duplicate window. Return 0 to send every submission. * * @param int $seconds Window in seconds. * @param array $envelope The envelope about to be sent. */ return (int) apply_filters( 'send4_duplicate_window', self::DEFAULT_WINDOW, $envelope ); } /** * Delete claims made at or before a moment, which is also what lets the * same person submit the same answers again once the window has passed. * * @param int $before Unix timestamp. * @return void */ private static function sweep( $before ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s AND CAST(option_value AS UNSIGNED) <= %d", $wpdb->esc_like( self::OPTION_PREFIX ) . '%', (int) $before ) ); } }