= self::limit( $action, $limit ) && (int) $state['until'] > time() ) { return self::error( (int) $state['until'] - time() ); } return true; } /** * Counts one attempt and returns an error when the limit is passed. * * @param string $action Action name. * @param string $subject What is counted. * @param int $limit Allowed attempts in the window. * @param int $window Window in seconds. * @return true|WP_Error */ public static function hit( $action, $subject, $limit, $window ) { $key = self::key( $action, $subject ); $state = get_transient( $key ); if ( ! is_array( $state ) || (int) $state['until'] <= time() ) { $state = array( 'count' => 0, 'until' => time() + $window, ); } if ( (int) $state['count'] >= self::limit( $action, $limit ) ) { return self::error( (int) $state['until'] - time() ); } ++$state['count']; set_transient( $key, $state, max( 1, (int) $state['until'] - time() ) ); return true; } /** * Forgets the attempts of a subject, for example after a correct password. * * @param string $action Action name. * @param string $subject What is counted. * @return void */ public static function clear( $action, $subject ) { delete_transient( self::key( $action, $subject ) ); } /** * Builds the "please wait" error. * * @param int $seconds Seconds until the visitor may try again. * @return WP_Error */ private static function error( $seconds ) { $minutes = max( 1, (int) ceil( $seconds / MINUTE_IN_SECONDS ) ); return new WP_Error( 'spacebay_too_many_attempts', sprintf( /* translators: %d: Number of minutes. */ _n( 'Too many attempts. Please wait %d minute and try again.', 'Too many attempts. Please wait %d minutes and try again.', $minutes, 'spacebay' ), $minutes ), array( 'status' => 429, 'retry_after' => $seconds, ) ); } }