/home/coopserp/.cagefs/tmp/phpRsuOE9
<?php
/**
* RSS2 Feed Template for displaying RSS2 Posts feed.
*
* @package WordPress
*/
header( 'Content-Type: ' . feed_content_type( 'rss2' ) . '; charset=' . get_option( 'blog_charset' ), true );
$more = 1;
echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>';
/**
* Fires between the xml and rss tags in a feed.
*
* @since 4.0.0
*
* @param string $context Type of feed. Possible values include 'rss2', 'rss2-comments',
* 'rdf', 'atom', and 'atom-comments'.
*/
do_action( 'rss_tag_pre', 'rss2' );
?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
<?php
/**
* Fires at the end of the RSS root to add namespaces.
*
* @since 2.0.0
*/
do_action( 'rss2_ns' );
?>
>
<channel>
<title><?php wp_title_rss(); ?></title>
<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
<link><?php bloginfo_rss( 'url' ); ?></link>
<description><?php bloginfo_rss( 'description' ); ?></description>
<lastBuildDate><?php echo get_feed_build_date( 'r' ); ?></lastBuildDate>
<language><?php bloginfo_rss( 'language' ); ?></language>
<sy:updatePeriod>
<?php
$duration = 'hourly';
/**
* Filters how often to update the RSS feed.
*
* @since 2.1.0
*
* @param string $duration The update period. Accepts 'hourly', 'daily', 'weekly', 'monthly',
* 'yearly'. Default 'hourly'.
*/
echo apply_filters( 'rss_update_period', $duration );
?>
</sy:updatePeriod>
<sy:updateFrequency>
<?php
$frequency = '1';
/**
* Filters the RSS update frequency.
*
* @since 2.1.0
*
* @param string $frequency An integer passed as a string representing the frequency
* of RSS updates within the update period. Default '1'.
*/
echo apply_filters( 'rss_update_frequency', $frequency );
?>
</sy:updateFrequency>
<?php
/**
* Fires at the end of the RSS2 Feed Header.
*
* @since 2.0.0
*/
do_action( 'rss2_head' );
while ( have_posts() ) :
the_post();
?>
<item>
<title><?php the_title_rss(); ?></title>
<link><?php the_permalink_rss(); ?></link>
<?php if ( get_comments_number() || comments_open() ) : ?>
<comments><?php comments_link_feed(); ?></comments>
<?php endif; ?>
<dc:creator><![CDATA[<?php the_author(); ?>]]></dc:creator>
<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
<?php the_category_rss( 'rss2' ); ?>
<guid isPermaLink="false"><?php the_guid(); ?></guid>
<?php if ( get_option( 'rss_use_excerpt' ) ) : ?>
<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
<?php else : ?>
<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
<?php $content = get_the_content_feed( 'rss2' ); ?>
<?php if ( strlen( $content ) > 0 ) : ?>
<content:encoded><![CDATA[<?php echo $content; ?>]]></content:encoded>
<?php else : ?>
<content:encoded><![CDATA[<?php the_excerpt_rss(); ?>]]></content:encoded>
<?php endif; ?>
<?php endif; ?>
<?php if ( get_comments_number() || comments_open() ) : ?>
<wfw:commentRss><?php echo esc_url( get_post_comments_feed_link( null, 'rss2' ) ); ?></wfw:commentRss>
<slash:comments><?php echo get_comments_number(); ?></slash:comments>
<?php endif; ?>
<?php rss_enclosure(); ?>
<?php
/**
* Fires at the end of each RSS2 feed item.
*
* @since 2.0.0
*/
do_action( 'rss2_item' );
?>
</item>
<?php endwhile; ?>
</channel>
</rss>
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.5 / WordPress
* @link https://www.openwall.com/phpass/
*/
#
# Portable PHP password hashing framework.
#
# Version 0.5.4 / WordPress.
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# The homepage URL for this framework is:
#
# http://www.openwall.com/phpass/
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.5 / WordPress
* @link https://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function __construct($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) {
$iteration_count_log2 = 8;
}
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime();
if (function_exists('getmypid')) {
$this->random_state .= getmypid();
}
}
function PasswordHash($iteration_count_log2, $portable_hashes)
{
self::__construct($iteration_count_log2, $portable_hashes);
}
function get_random_bytes($count)
{
$output = '';
if (@is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .= md5($this->random_state, TRUE);
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count) {
$value |= ord($input[$i]) << 8;
}
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count) {
break;
}
if ($i < $count) {
$value |= ord($input[$i]) << 16;
}
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count) {
break;
}
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 + 5,
30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) === $output) {
$output = '*1';
}
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id !== '$P$' && $id !== '$H$') {
return $output;
}
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30) {
return $output;
}
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) !== 8) {
return $output;
}
# We were kind of forced to use MD5 here since it's the only
# cryptographic primitive that was available in all versions
# of PHP in use. To implement our own low-level crypto in PHP
# would have resulted in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr((int)(ord('0') + $this->iteration_count_log2 / 10));
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
if ( strlen( $password ) > 4096 ) {
return '*';
}
$random = '';
if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) === 60) {
return $hash;
}
}
if (strlen($random) < 6) {
$random = $this->get_random_bytes(6);
}
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) === 34) {
return $hash;
}
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
if ( strlen( $password ) > 4096 ) {
return false;
}
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] === '*') {
$hash = crypt($password, $stored_hash);
}
# This is not constant-time. In order to keep the code simple,
# for timing safety we currently rely on the salts being
# unpredictable, which they are at least in the non-fallback
# cases (that is, when we use /dev/urandom and bcrypt).
return $hash === $stored_hash;
}
}
<?php
/**
* RSS 1 RDF Feed Template for displaying RSS 1 Posts feed.
*
* @package WordPress
*/
header( 'Content-Type: ' . feed_content_type( 'rdf' ) . '; charset=' . get_option( 'blog_charset' ), true );
$more = 1;
echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>';
/** This action is documented in wp-includes/feed-rss2.php */
do_action( 'rss_tag_pre', 'rdf' );
?>
<rdf:RDF
xmlns="http://purl.org/rss/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:admin="http://webns.net/mvcb/"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
<?php
/**
* Fires at the end of the feed root to add namespaces.
*
* @since 2.0.0
*/
do_action( 'rdf_ns' );
?>
>
<channel rdf:about="<?php bloginfo_rss( 'url' ); ?>">
<title><?php wp_title_rss(); ?></title>
<link><?php bloginfo_rss( 'url' ); ?></link>
<description><?php bloginfo_rss( 'description' ); ?></description>
<dc:date><?php echo get_feed_build_date( 'Y-m-d\TH:i:s\Z' ); ?> </dc:date>
<sy:updatePeriod>
<?php
/** This filter is documented in wp-includes/feed-rss2.php */
echo apply_filters( 'rss_update_period', 'hourly' );
?>
</sy:updatePeriod>
<sy:updateFrequency>
<?php
/** This filter is documented in wp-includes/feed-rss2.php */
echo apply_filters( 'rss_update_frequency', '1' );
?>
</sy:updateFrequency>
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
<?php
/**
* Fires at the end of the RDF feed header.
*
* @since 2.0.0
*/
do_action( 'rdf_header' );
?>
<items>
<rdf:Seq>
<?php
while ( have_posts() ) :
the_post();
?>
<rdf:li rdf:resource="<?php the_permalink_rss(); ?>"/>
<?php endwhile; ?>
</rdf:Seq>
</items>
</channel>
<?php
rewind_posts();
while ( have_posts() ) :
the_post();
?>
<item rdf:about="<?php the_permalink_rss(); ?>">
<title><?php the_title_rss(); ?></title>
<link><?php the_permalink_rss(); ?></link>
<dc:creator><![CDATA[<?php the_author(); ?>]]></dc:creator>
<dc:date><?php echo mysql2date( 'Y-m-d\TH:i:s\Z', $post->post_date_gmt, false ); ?></dc:date>
<?php the_category_rss( 'rdf' ); ?>
<?php if ( get_option( 'rss_use_excerpt' ) ) : ?>
<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
<?php else : ?>
<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
<content:encoded><![CDATA[<?php the_content_feed( 'rdf' ); ?>]]></content:encoded>
<?php endif; ?>
<?php
/**
* Fires at the end of each RDF feed item.
*
* @since 2.0.0
*/
do_action( 'rdf_item' );
?>
</item>
<?php endwhile; ?>
</rdf:RDF>
[02-Dec-2025 10:41:45 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Translation_File" not found in /home/coopserp/public_html/wp-includes/l10n/class-wp-translation-file-mo.php:15
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/l10n/class-wp-translation-file-mo.php on line 15
[02-Dec-2025 10:41:46 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Translation_File" not found in /home/coopserp/public_html/wp-includes/l10n/class-wp-translation-file-php.php:15
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/l10n/class-wp-translation-file-php.php on line 15
<?php
/**
* I18N: WP_Translation_File_MO class.
*
* @package WordPress
* @subpackage I18N
* @since 6.5.0
*/
/**
* Class WP_Translation_File_MO.
*
* @since 6.5.0
*/
class WP_Translation_File_MO extends WP_Translation_File {
/**
* Endian value.
*
* V for little endian, N for big endian, or false.
*
* Used for unpack().
*
* @since 6.5.0
* @var false|'V'|'N'
*/
protected $uint32 = false;
/**
* The magic number of the GNU message catalog format.
*
* @since 6.5.0
* @var int
*/
const MAGIC_MARKER = 0x950412de;
/**
* Detects endian and validates file.
*
* @since 6.5.0
*
* @param string $header File contents.
* @return false|'V'|'N' V for little endian, N for big endian, or false on failure.
*/
protected function detect_endian_and_validate_file( string $header ) {
$big = unpack( 'N', $header );
if ( false === $big ) {
return false;
}
$big = reset( $big );
if ( false === $big ) {
return false;
}
$little = unpack( 'V', $header );
if ( false === $little ) {
return false;
}
$little = reset( $little );
if ( false === $little ) {
return false;
}
// Force cast to an integer as it can be a float on x86 systems. See https://core.trac.wordpress.org/ticket/60678.
if ( (int) self::MAGIC_MARKER === $big ) {
return 'N';
}
// Force cast to an integer as it can be a float on x86 systems. See https://core.trac.wordpress.org/ticket/60678.
if ( (int) self::MAGIC_MARKER === $little ) {
return 'V';
}
$this->error = 'Magic marker does not exist';
return false;
}
/**
* Parses the file.
*
* @since 6.5.0
*
* @return bool True on success, false otherwise.
*/
protected function parse_file(): bool {
$this->parsed = true;
$file_contents = file_get_contents( $this->file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
if ( false === $file_contents ) {
return false;
}
$file_length = strlen( $file_contents );
if ( $file_length < 24 ) {
$this->error = 'Invalid data';
return false;
}
$this->uint32 = $this->detect_endian_and_validate_file( substr( $file_contents, 0, 4 ) );
if ( false === $this->uint32 ) {
return false;
}
$offsets = substr( $file_contents, 4, 24 );
if ( false === $offsets ) {
return false;
}
$offsets = unpack( "{$this->uint32}rev/{$this->uint32}total/{$this->uint32}originals_addr/{$this->uint32}translations_addr/{$this->uint32}hash_length/{$this->uint32}hash_addr", $offsets );
if ( false === $offsets ) {
return false;
}
$offsets['originals_length'] = $offsets['translations_addr'] - $offsets['originals_addr'];
$offsets['translations_length'] = $offsets['hash_addr'] - $offsets['translations_addr'];
if ( $offsets['rev'] > 0 ) {
$this->error = 'Unsupported revision';
return false;
}
if ( $offsets['translations_addr'] > $file_length || $offsets['originals_addr'] > $file_length ) {
$this->error = 'Invalid data';
return false;
}
// Load the Originals.
$original_data = str_split( substr( $file_contents, $offsets['originals_addr'], $offsets['originals_length'] ), 8 );
$translations_data = str_split( substr( $file_contents, $offsets['translations_addr'], $offsets['translations_length'] ), 8 );
foreach ( array_keys( $original_data ) as $i ) {
$o = unpack( "{$this->uint32}length/{$this->uint32}pos", $original_data[ $i ] );
$t = unpack( "{$this->uint32}length/{$this->uint32}pos", $translations_data[ $i ] );
if ( false === $o || false === $t ) {
continue;
}
$original = substr( $file_contents, $o['pos'], $o['length'] );
$translation = substr( $file_contents, $t['pos'], $t['length'] );
// GlotPress bug.
$translation = rtrim( $translation, "\0" );
// Metadata about the MO file is stored in the first translation entry.
if ( '' === $original ) {
foreach ( explode( "\n", $translation ) as $meta_line ) {
if ( '' === $meta_line || ! str_contains( $meta_line, ':' ) ) {
continue;
}
list( $name, $value ) = array_map( 'trim', explode( ':', $meta_line, 2 ) );
$this->headers[ strtolower( $name ) ] = $value;
}
} else {
/*
* In MO files, the key normally contains both singular and plural versions.
* However, this just adds the singular string for lookup,
* which caters for cases where both __( 'Product' ) and _n( 'Product', 'Products' )
* are used and the translation is expected to be the same for both.
*/
$parts = explode( "\0", (string) $original );
$this->entries[ $parts[0] ] = $translation;
}
}
return true;
}
/**
* Exports translation contents as a string.
*
* @since 6.5.0
*
* @return string Translation file contents.
*/
public function export(): string {
// Prefix the headers as the first key.
$headers_string = '';
foreach ( $this->headers as $header => $value ) {
$headers_string .= "{$header}: $value\n";
}
$entries = array_merge( array( '' => $headers_string ), $this->entries );
$entry_count = count( $entries );
if ( false === $this->uint32 ) {
$this->uint32 = 'V';
}
$bytes_for_entries = $entry_count * 4 * 2;
// Pair of 32bit ints per entry.
$originals_addr = 28; /* header */
$translations_addr = $originals_addr + $bytes_for_entries;
$hash_addr = $translations_addr + $bytes_for_entries;
$entry_offsets = $hash_addr;
$file_header = pack(
$this->uint32 . '*',
// Force cast to an integer as it can be a float on x86 systems. See https://core.trac.wordpress.org/ticket/60678.
(int) self::MAGIC_MARKER,
0, /* rev */
$entry_count,
$originals_addr,
$translations_addr,
0, /* hash_length */
$hash_addr
);
$o_entries = '';
$t_entries = '';
$o_addr = '';
$t_addr = '';
foreach ( array_keys( $entries ) as $original ) {
$o_addr .= pack( $this->uint32 . '*', strlen( $original ), $entry_offsets );
$entry_offsets += strlen( $original ) + 1;
$o_entries .= $original . "\0";
}
foreach ( $entries as $translations ) {
$t_addr .= pack( $this->uint32 . '*', strlen( $translations ), $entry_offsets );
$entry_offsets += strlen( $translations ) + 1;
$t_entries .= $translations . "\0";
}
return $file_header . $o_addr . $t_addr . $o_entries . $t_entries;
}
}
<?php
/**
* I18N: WP_Translation_File class.
*
* @package WordPress
* @subpackage I18N
* @since 6.5.0
*/
/**
* Class WP_Translation_File.
*
* @since 6.5.0
*/
abstract class WP_Translation_File {
/**
* List of headers.
*
* @since 6.5.0
* @var array<string, string>
*/
protected $headers = array();
/**
* Whether file has been parsed.
*
* @since 6.5.0
* @var bool
*/
protected $parsed = false;
/**
* Error information.
*
* @since 6.5.0
* @var string|null Error message or null if no error.
*/
protected $error;
/**
* File name.
*
* @since 6.5.0
* @var string
*/
protected $file = '';
/**
* Translation entries.
*
* @since 6.5.0
* @var array<string, string>
*/
protected $entries = array();
/**
* Plural forms function.
*
* @since 6.5.0
* @var callable|null Plural forms.
*/
protected $plural_forms = null;
/**
* Constructor.
*
* @since 6.5.0
*
* @param string $file File to load.
*/
protected function __construct( string $file ) {
$this->file = $file;
}
/**
* Creates a new WP_Translation_File instance for a given file.
*
* @since 6.5.0
*
* @param string $file File name.
* @param string|null $filetype Optional. File type. Default inferred from file name.
* @return false|WP_Translation_File
*/
public static function create( string $file, ?string $filetype = null ) {
if ( ! is_readable( $file ) ) {
return false;
}
if ( null === $filetype ) {
$pos = strrpos( $file, '.' );
if ( false !== $pos ) {
$filetype = substr( $file, $pos + 1 );
}
}
switch ( $filetype ) {
case 'mo':
return new WP_Translation_File_MO( $file );
case 'php':
return new WP_Translation_File_PHP( $file );
default:
return false;
}
}
/**
* Creates a new WP_Translation_File instance for a given file.
*
* @since 6.5.0
*
* @param string $file Source file name.
* @param string $filetype Desired target file type.
* @return string|false Transformed translation file contents on success, false otherwise.
*/
public static function transform( string $file, string $filetype ) {
$source = self::create( $file );
if ( false === $source ) {
return false;
}
switch ( $filetype ) {
case 'mo':
$destination = new WP_Translation_File_MO( '' );
break;
case 'php':
$destination = new WP_Translation_File_PHP( '' );
break;
default:
return false;
}
$success = $destination->import( $source );
if ( ! $success ) {
return false;
}
return $destination->export();
}
/**
* Returns all headers.
*
* @since 6.5.0
*
* @return array<string, string> Headers.
*/
public function headers(): array {
if ( ! $this->parsed ) {
$this->parse_file();
}
return $this->headers;
}
/**
* Returns all entries.
*
* @since 6.5.0
*
* @return array<string, string[]> Entries.
*/
public function entries(): array {
if ( ! $this->parsed ) {
$this->parse_file();
}
return $this->entries;
}
/**
* Returns the current error information.
*
* @since 6.5.0
*
* @return string|null Error message or null if no error.
*/
public function error() {
return $this->error;
}
/**
* Returns the file name.
*
* @since 6.5.0
*
* @return string File name.
*/
public function get_file(): string {
return $this->file;
}
/**
* Translates a given string.
*
* @since 6.5.0
*
* @param string $text String to translate.
* @return false|string Translation(s) on success, false otherwise.
*/
public function translate( string $text ) {
if ( ! $this->parsed ) {
$this->parse_file();
}
return $this->entries[ $text ] ?? false;
}
/**
* Returns the plural form for a given number.
*
* @since 6.5.0
*
* @param int $number Count.
* @return int Plural form.
*/
public function get_plural_form( int $number ): int {
if ( ! $this->parsed ) {
$this->parse_file();
}
if ( null === $this->plural_forms && isset( $this->headers['plural-forms'] ) ) {
$expression = $this->get_plural_expression_from_header( $this->headers['plural-forms'] );
$this->plural_forms = $this->make_plural_form_function( $expression );
}
if ( is_callable( $this->plural_forms ) ) {
/**
* Plural form.
*
* @var int $result Plural form.
*/
$result = call_user_func( $this->plural_forms, $number );
return $result;
}
// Default plural form matches English, only "One" is considered singular.
return ( 1 === $number ? 0 : 1 );
}
/**
* Returns the plural forms expression as a tuple.
*
* @since 6.5.0
*
* @param string $header Plural-Forms header string.
* @return string Plural forms expression.
*/
protected function get_plural_expression_from_header( string $header ): string {
if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) {
return trim( $matches[2] );
}
return 'n != 1';
}
/**
* Makes a function, which will return the right translation index, according to the
* plural forms header.
*
* @since 6.5.0
*
* @param string $expression Plural form expression.
* @return callable(int $num): int Plural forms function.
*/
protected function make_plural_form_function( string $expression ): callable {
try {
$handler = new Plural_Forms( rtrim( $expression, ';' ) );
return array( $handler, 'get' );
} catch ( Exception $e ) {
// Fall back to default plural-form function.
return $this->make_plural_form_function( 'n != 1' );
}
}
/**
* Imports translations from another file.
*
* @since 6.5.0
*
* @param WP_Translation_File $source Source file.
* @return bool True on success, false otherwise.
*/
protected function import( WP_Translation_File $source ): bool {
if ( null !== $source->error() ) {
return false;
}
$this->headers = $source->headers();
$this->entries = $source->entries();
$this->error = $source->error();
return null === $this->error;
}
/**
* Parses the file.
*
* @since 6.5.0
*/
abstract protected function parse_file();
/**
* Exports translation contents as a string.
*
* @since 6.5.0
*
* @return string Translation file contents.
*/
abstract public function export();
}
<?php
/**
* I18N: WP_Translations class.
*
* @package WordPress
* @subpackage I18N
* @since 6.5.0
*/
/**
* Class WP_Translations.
*
* @since 6.5.0
*
* @property-read array<string, string> $headers
* @property-read array<string, string[]> $entries
*/
class WP_Translations {
/**
* Text domain.
*
* @since 6.5.0
* @var string
*/
protected $textdomain = 'default';
/**
* Translation controller instance.
*
* @since 6.5.0
* @var WP_Translation_Controller
*/
protected $controller;
/**
* Constructor.
*
* @since 6.5.0
*
* @param WP_Translation_Controller $controller I18N controller.
* @param string $textdomain Optional. Text domain. Default 'default'.
*/
public function __construct( WP_Translation_Controller $controller, string $textdomain = 'default' ) {
$this->controller = $controller;
$this->textdomain = $textdomain;
}
/**
* Magic getter for backward compatibility.
*
* @since 6.5.0
*
* @param string $name Property name.
* @return mixed
*/
public function __get( string $name ) {
if ( 'entries' === $name ) {
$entries = $this->controller->get_entries( $this->textdomain );
$result = array();
foreach ( $entries as $original => $translations ) {
$result[] = $this->make_entry( $original, $translations );
}
return $result;
}
if ( 'headers' === $name ) {
return $this->controller->get_headers( $this->textdomain );
}
return null;
}
/**
* Builds a Translation_Entry from original string and translation strings.
*
* @see MO::make_entry()
*
* @since 6.5.0
*
* @param string $original Original string to translate from MO file. Might contain
* 0x04 as context separator or 0x00 as singular/plural separator.
* @param string $translations Translation strings from MO file.
* @return Translation_Entry Entry instance.
*/
private function make_entry( $original, $translations ): Translation_Entry {
$entry = new Translation_Entry();
// Look for context, separated by \4.
$parts = explode( "\4", $original );
if ( isset( $parts[1] ) ) {
$original = $parts[1];
$entry->context = $parts[0];
}
$entry->singular = $original;
$entry->translations = explode( "\0", $translations );
$entry->is_plural = count( $entry->translations ) > 1;
return $entry;
}
/**
* Translates a plural string.
*
* @since 6.5.0
*
* @param string|null $singular Singular string.
* @param string|null $plural Plural string.
* @param int|float $count Count. Should be an integer, but some plugins pass floats.
* @param string|null $context Context.
* @return string|null Translation if it exists, or the unchanged singular string.
*/
public function translate_plural( $singular, $plural, $count = 1, $context = '' ) {
if ( null === $singular || null === $plural ) {
return $singular;
}
$translation = $this->controller->translate_plural( array( $singular, $plural ), (int) $count, (string) $context, $this->textdomain );
if ( false !== $translation ) {
return $translation;
}
// Fall back to the original with English grammar rules.
return ( 1 === $count ? $singular : $plural );
}
/**
* Translates a singular string.
*
* @since 6.5.0
*
* @param string|null $singular Singular string.
* @param string|null $context Context.
* @return string|null Translation if it exists, or the unchanged singular string
*/
public function translate( $singular, $context = '' ) {
if ( null === $singular ) {
return null;
}
$translation = $this->controller->translate( $singular, (string) $context, $this->textdomain );
if ( false !== $translation ) {
return $translation;
}
// Fall back to the original.
return $singular;
}
}
<?php
/**
* I18N: WP_Translation_File_PHP class.
*
* @package WordPress
* @subpackage I18N
* @since 6.5.0
*/
/**
* Class WP_Translation_File_PHP.
*
* @since 6.5.0
*/
class WP_Translation_File_PHP extends WP_Translation_File {
/**
* Parses the file.
*
* @since 6.5.0
*/
protected function parse_file() {
$this->parsed = true;
$result = include $this->file;
if ( ! $result || ! is_array( $result ) ) {
$this->error = 'Invalid data';
return;
}
if ( isset( $result['messages'] ) && is_array( $result['messages'] ) ) {
foreach ( $result['messages'] as $original => $translation ) {
$this->entries[ (string) $original ] = $translation;
}
unset( $result['messages'] );
}
$this->headers = array_change_key_case( $result );
}
/**
* Exports translation contents as a string.
*
* @since 6.5.0
*
* @return string Translation file contents.
*/
public function export(): string {
$data = array_merge( $this->headers, array( 'messages' => $this->entries ) );
return '<?php' . PHP_EOL . 'return ' . $this->var_export( $data ) . ';' . PHP_EOL;
}
/**
* Outputs or returns a parsable string representation of a variable.
*
* Like {@see var_export()} but "minified", using short array syntax
* and no newlines.
*
* @since 6.5.0
*
* @param mixed $value The variable you want to export.
* @return string The variable representation.
*/
private function var_export( $value ): string {
if ( ! is_array( $value ) ) {
return var_export( $value, true );
}
$entries = array();
$is_list = array_is_list( $value );
foreach ( $value as $key => $val ) {
$entries[] = $is_list ? $this->var_export( $val ) : var_export( $key, true ) . '=>' . $this->var_export( $val );
}
return '[' . implode( ',', $entries ) . ']';
}
}
<?php
/**
* I18N: WP_Translation_Controller class.
*
* @package WordPress
* @subpackage I18N
* @since 6.5.0
*/
/**
* Class WP_Translation_Controller.
*
* @since 6.5.0
*/
final class WP_Translation_Controller {
/**
* Current locale.
*
* @since 6.5.0
* @var string
*/
protected $current_locale = 'en_US';
/**
* Map of loaded translations per locale and text domain.
*
* [ Locale => [ Textdomain => [ ..., ... ] ] ]
*
* @since 6.5.0
* @var array<string, array<string, WP_Translation_File[]>>
*/
protected $loaded_translations = array();
/**
* List of loaded translation files.
*
* [ Filename => [ Locale => [ Textdomain => WP_Translation_File ] ] ]
*
* @since 6.5.0
* @var array<string, array<string, array<string, WP_Translation_File|false>>>
*/
protected $loaded_files = array();
/**
* Container for the main instance of the class.
*
* @since 6.5.0
* @var WP_Translation_Controller|null
*/
private static $instance = null;
/**
* Utility method to retrieve the main instance of the class.
*
* The instance will be created if it does not exist yet.
*
* @since 6.5.0
*
* @return WP_Translation_Controller
*/
public static function get_instance(): WP_Translation_Controller {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Returns the current locale.
*
* @since 6.5.0
*
* @return string Locale.
*/
public function get_locale(): string {
return $this->current_locale;
}
/**
* Sets the current locale.
*
* @since 6.5.0
*
* @param string $locale Locale.
*/
public function set_locale( string $locale ) {
$this->current_locale = $locale;
}
/**
* Loads a translation file for a given text domain.
*
* @since 6.5.0
*
* @param string $translation_file Translation file.
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Default current locale.
* @return bool True on success, false otherwise.
*/
public function load_file( string $translation_file, string $textdomain = 'default', ?string $locale = null ): bool {
if ( null === $locale ) {
$locale = $this->current_locale;
}
$translation_file = realpath( $translation_file );
if ( false === $translation_file ) {
return false;
}
if (
isset( $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] ) &&
false !== $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ]
) {
return null === $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ]->error();
}
if (
isset( $this->loaded_files[ $translation_file ][ $locale ] ) &&
array() !== $this->loaded_files[ $translation_file ][ $locale ]
) {
$moe = reset( $this->loaded_files[ $translation_file ][ $locale ] );
} else {
$moe = WP_Translation_File::create( $translation_file );
if ( false === $moe || null !== $moe->error() ) {
$moe = false;
}
}
$this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] = $moe;
if ( ! $moe instanceof WP_Translation_File ) {
return false;
}
if ( ! isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) {
$this->loaded_translations[ $locale ][ $textdomain ] = array();
}
$this->loaded_translations[ $locale ][ $textdomain ][] = $moe;
return true;
}
/**
* Unloads a translation file for a given text domain.
*
* @since 6.5.0
*
* @param WP_Translation_File|string $file Translation file instance or file name.
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Defaults to all locales.
* @return bool True on success, false otherwise.
*/
public function unload_file( $file, string $textdomain = 'default', ?string $locale = null ): bool {
if ( is_string( $file ) ) {
$file = realpath( $file );
}
if ( null !== $locale ) {
if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) {
foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $i => $moe ) {
if ( $file === $moe || $file === $moe->get_file() ) {
unset( $this->loaded_translations[ $locale ][ $textdomain ][ $i ] );
unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] );
return true;
}
}
}
return true;
}
foreach ( $this->loaded_translations as $l => $domains ) {
if ( ! isset( $domains[ $textdomain ] ) ) {
continue;
}
foreach ( $domains[ $textdomain ] as $i => $moe ) {
if ( $file === $moe || $file === $moe->get_file() ) {
unset( $this->loaded_translations[ $l ][ $textdomain ][ $i ] );
unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] );
return true;
}
}
}
return false;
}
/**
* Unloads all translation files for a given text domain.
*
* @since 6.5.0
*
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Defaults to all locales.
* @return bool True on success, false otherwise.
*/
public function unload_textdomain( string $textdomain = 'default', ?string $locale = null ): bool {
$unloaded = false;
if ( null !== $locale ) {
if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) {
$unloaded = true;
foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $moe ) {
unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] );
}
}
unset( $this->loaded_translations[ $locale ][ $textdomain ] );
return $unloaded;
}
foreach ( $this->loaded_translations as $l => $domains ) {
if ( ! isset( $domains[ $textdomain ] ) ) {
continue;
}
$unloaded = true;
foreach ( $domains[ $textdomain ] as $moe ) {
unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] );
}
unset( $this->loaded_translations[ $l ][ $textdomain ] );
}
return $unloaded;
}
/**
* Determines whether translations are loaded for a given text domain.
*
* @since 6.5.0
*
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Default current locale.
* @return bool True if there are any loaded translations, false otherwise.
*/
public function is_textdomain_loaded( string $textdomain = 'default', ?string $locale = null ): bool {
if ( null === $locale ) {
$locale = $this->current_locale;
}
return isset( $this->loaded_translations[ $locale ][ $textdomain ] ) &&
array() !== $this->loaded_translations[ $locale ][ $textdomain ];
}
/**
* Translates a singular string.
*
* @since 6.5.0
*
* @param string $text Text to translate.
* @param string $context Optional. Context for the string. Default empty string.
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Default current locale.
* @return string|false Translation on success, false otherwise.
*/
public function translate( string $text, string $context = '', string $textdomain = 'default', ?string $locale = null ) {
if ( '' !== $context ) {
$context .= "\4";
}
$translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale );
if ( false === $translation ) {
return false;
}
return $translation['entries'][0];
}
/**
* Translates plurals.
*
* Checks both singular+plural combinations as well as just singulars,
* in case the translation file does not store the plural.
*
* @since 6.5.0
*
* @param array $plurals {
* Pair of singular and plural translations.
*
* @type string $0 Singular translation.
* @type string $1 Plural translation.
* }
* @param int $number Number of items.
* @param string $context Optional. Context for the string. Default empty string.
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string|null $locale Optional. Locale. Default current locale.
* @return string|false Translation on success, false otherwise.
*/
public function translate_plural( array $plurals, int $number, string $context = '', string $textdomain = 'default', ?string $locale = null ) {
if ( '' !== $context ) {
$context .= "\4";
}
$text = implode( "\0", $plurals );
$translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale );
if ( false === $translation ) {
$text = $plurals[0];
$translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale );
if ( false === $translation ) {
return false;
}
}
/** @var WP_Translation_File $source */
$source = $translation['source'];
$num = $source->get_plural_form( $number );
// See \Translations::translate_plural().
return $translation['entries'][ $num ] ?? $translation['entries'][0];
}
/**
* Returns all existing headers for a given text domain.
*
* @since 6.5.0
*
* @param string $textdomain Optional. Text domain. Default 'default'.
* @return array<string, string> Headers.
*/
public function get_headers( string $textdomain = 'default' ): array {
if ( array() === $this->loaded_translations ) {
return array();
}
$headers = array();
foreach ( $this->get_files( $textdomain ) as $moe ) {
foreach ( $moe->headers() as $header => $value ) {
$headers[ $this->normalize_header( $header ) ] = $value;
}
}
return $headers;
}
/**
* Normalizes header names to be capitalized.
*
* @since 6.5.0
*
* @param string $header Header name.
* @return string Normalized header name.
*/
protected function normalize_header( string $header ): string {
$parts = explode( '-', $header );
$parts = array_map( 'ucfirst', $parts );
return implode( '-', $parts );
}
/**
* Returns all entries for a given text domain.
*
* @since 6.5.0
*
* @param string $textdomain Optional. Text domain. Default 'default'.
* @return array<string, string> Entries.
*/
public function get_entries( string $textdomain = 'default' ): array {
if ( array() === $this->loaded_translations ) {
return array();
}
$entries = array();
foreach ( $this->get_files( $textdomain ) as $moe ) {
$entries = array_merge( $entries, $moe->entries() );
}
return $entries;
}
/**
* Locates translation for a given string and text domain.
*
* @since 6.5.0
*
* @param string $singular Singular translation.
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Default current locale.
* @return array{source: WP_Translation_File, entries: string[]}|false {
* Translations on success, false otherwise.
*
* @type WP_Translation_File $source Translation file instance.
* @type string[] $entries Array of translation entries.
* }
*/
protected function locate_translation( string $singular, string $textdomain = 'default', ?string $locale = null ) {
if ( array() === $this->loaded_translations ) {
return false;
}
// Find the translation in all loaded files for this text domain.
foreach ( $this->get_files( $textdomain, $locale ) as $moe ) {
$translation = $moe->translate( $singular );
if ( false !== $translation ) {
return array(
'entries' => explode( "\0", $translation ),
'source' => $moe,
);
}
if ( null !== $moe->error() ) {
// Unload this file, something is wrong.
$this->unload_file( $moe, $textdomain, $locale );
}
}
// Nothing could be found.
return false;
}
/**
* Returns all translation files for a given text domain.
*
* @since 6.5.0
*
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param string $locale Optional. Locale. Default current locale.
* @return WP_Translation_File[] List of translation files.
*/
protected function get_files( string $textdomain = 'default', ?string $locale = null ): array {
if ( null === $locale ) {
$locale = $this->current_locale;
}
return $this->loaded_translations[ $locale ][ $textdomain ] ?? array();
}
/**
* Returns a boolean to indicate whether a translation exists for a given string with optional text domain and locale.
*
* @since 6.7.0
*
* @param string $singular Singular translation to check.
* @param string $textdomain Optional. Text domain. Default 'default'.
* @param ?string $locale Optional. Locale. Default current locale.
* @return bool True if the translation exists, false otherwise.
*/
public function has_translation( string $singular, string $textdomain = 'default', ?string $locale = null ): bool {
if ( null === $locale ) {
$locale = $this->current_locale;
}
return false !== $this->locate_translation( $singular, $textdomain, $locale );
}
}
<?php
/**
* User API: WP_Role class
*
* @package WordPress
* @subpackage Users
* @since 4.4.0
*/
/**
* Core class used to extend the user roles API.
*
* @since 2.0.0
*/
#[AllowDynamicProperties]
class WP_Role {
/**
* Role name.
*
* @since 2.0.0
* @var string
*/
public $name;
/**
* List of capabilities the role contains.
*
* @since 2.0.0
* @var bool[] Array of key/value pairs where keys represent a capability name and boolean values
* represent whether the role has that capability.
*/
public $capabilities;
/**
* Constructor - Set up object properties.
*
* The list of capabilities must have the key as the name of the capability
* and the value a boolean of whether it is granted to the role.
*
* @since 2.0.0
*
* @param string $role Role name.
* @param bool[] $capabilities Array of key/value pairs where keys represent a capability name and boolean values
* represent whether the role has that capability.
*/
public function __construct( $role, $capabilities ) {
$this->name = $role;
$this->capabilities = $capabilities;
}
/**
* Assign role a capability.
*
* @since 2.0.0
*
* @param string $cap Capability name.
* @param bool $grant Whether role has capability privilege.
*/
public function add_cap( $cap, $grant = true ) {
$this->capabilities[ $cap ] = $grant;
wp_roles()->add_cap( $this->name, $cap, $grant );
}
/**
* Removes a capability from a role.
*
* @since 2.0.0
*
* @param string $cap Capability name.
*/
public function remove_cap( $cap ) {
unset( $this->capabilities[ $cap ] );
wp_roles()->remove_cap( $this->name, $cap );
}
/**
* Determines whether the role has the given capability.
*
* @since 2.0.0
*
* @param string $cap Capability name.
* @return bool Whether the role has the given capability.
*/
public function has_cap( $cap ) {
/**
* Filters which capabilities a role has.
*
* @since 2.0.0
*
* @param bool[] $capabilities Array of key/value pairs where keys represent a capability name and boolean values
* represent whether the role has that capability.
* @param string $cap Capability name.
* @param string $name Role name.
*/
$capabilities = apply_filters( 'role_has_cap', $this->capabilities, $cap, $this->name );
if ( ! empty( $capabilities[ $cap ] ) ) {
return $capabilities[ $cap ];
} else {
return false;
}
}
}
<?php
/**
* Core Widgets API
*
* This API is used for creating dynamic sidebar without hardcoding functionality into
* themes.
*
* Includes both internal WordPress routines and theme-use routines.
*
* This functionality was found in a plugin before the WordPress 2.2 release, which
* included it in the core from that point on.
*
* @link https://wordpress.org/documentation/article/manage-wordpress-widgets/
* @link https://developer.wordpress.org/themes/functionality/widgets/
*
* @package WordPress
* @subpackage Widgets
* @since 2.2.0
*/
//
// Global Variables.
//
/** @ignore */
global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
/**
* Stores the sidebars, since many themes can have more than one.
*
* @since 2.2.0
*
* @global array $wp_registered_sidebars The registered sidebars.
*/
$wp_registered_sidebars = array();
/**
* Stores the registered widgets.
*
* @since 2.2.0
*
* @global array $wp_registered_widgets The registered widgets.
*/
$wp_registered_widgets = array();
/**
* Stores the registered widget controls (options).
*
* @since 2.2.0
*
* @global array $wp_registered_widget_controls The registered widget controls.
*/
$wp_registered_widget_controls = array();
/**
* Stores the registered widget updates.
*
* @since 2.8.0
*
* @global array $wp_registered_widget_updates The registered widget updates.
*/
$wp_registered_widget_updates = array();
/**
* Private
*
* @global array $_wp_sidebars_widgets
*/
$_wp_sidebars_widgets = array();
/**
* Private
*
* @global array $_wp_deprecated_widgets_callbacks
*/
$GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
'wp_widget_pages',
'wp_widget_pages_control',
'wp_widget_calendar',
'wp_widget_calendar_control',
'wp_widget_archives',
'wp_widget_archives_control',
'wp_widget_links',
'wp_widget_meta',
'wp_widget_meta_control',
'wp_widget_search',
'wp_widget_recent_entries',
'wp_widget_recent_entries_control',
'wp_widget_tag_cloud',
'wp_widget_tag_cloud_control',
'wp_widget_categories',
'wp_widget_categories_control',
'wp_widget_text',
'wp_widget_text_control',
'wp_widget_rss',
'wp_widget_rss_control',
'wp_widget_recent_comments',
'wp_widget_recent_comments_control',
);
//
// Template tags & API functions.
//
/**
* Registers a widget.
*
* Registers a WP_Widget widget
*
* @since 2.8.0
* @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
* instead of simply a `WP_Widget` subclass name.
*
* @see WP_Widget
*
* @global WP_Widget_Factory $wp_widget_factory
*
* @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
*/
function register_widget( $widget ) {
global $wp_widget_factory;
$wp_widget_factory->register( $widget );
}
/**
* Unregisters a widget.
*
* Unregisters a WP_Widget widget. Useful for un-registering default widgets.
* Run within a function hooked to the {@see 'widgets_init'} action.
*
* @since 2.8.0
* @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
* instead of simply a `WP_Widget` subclass name.
*
* @see WP_Widget
*
* @global WP_Widget_Factory $wp_widget_factory
*
* @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
*/
function unregister_widget( $widget ) {
global $wp_widget_factory;
$wp_widget_factory->unregister( $widget );
}
/**
* Creates multiple sidebars.
*
* If you wanted to quickly create multiple sidebars for a theme or internally.
* This function will allow you to do so. If you don't pass the 'name' and/or
* 'id' in `$args`, then they will be built for you.
*
* @since 2.2.0
*
* @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
*
* @global array $wp_registered_sidebars The new sidebars are stored in this array by sidebar ID.
*
* @param int $number Optional. Number of sidebars to create. Default 1.
* @param array|string $args {
* Optional. Array or string of arguments for building a sidebar.
*
* @type string $id The base string of the unique identifier for each sidebar. If provided, and multiple
* sidebars are being defined, the ID will have "-2" appended, and so on.
* Default 'sidebar-' followed by the number the sidebar creation is currently at.
* @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
* more than one sidebar, include '%d' in the string as a placeholder for the uniquely
* assigned number for each sidebar.
* Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
* }
*/
function register_sidebars( $number = 1, $args = array() ) {
global $wp_registered_sidebars;
$number = (int) $number;
if ( is_string( $args ) ) {
parse_str( $args, $args );
}
for ( $i = 1; $i <= $number; $i++ ) {
$_args = $args;
if ( $number > 1 ) {
if ( isset( $args['name'] ) ) {
$_args['name'] = sprintf( $args['name'], $i );
} else {
/* translators: %d: Sidebar number. */
$_args['name'] = sprintf( __( 'Sidebar %d' ), $i );
}
} else {
$_args['name'] = isset( $args['name'] ) ? $args['name'] : __( 'Sidebar' );
}
/*
* Custom specified ID's are suffixed if they exist already.
* Automatically generated sidebar names need to be suffixed regardless starting at -0.
*/
if ( isset( $args['id'] ) ) {
$_args['id'] = $args['id'];
$n = 2; // Start at -2 for conflicting custom IDs.
while ( is_registered_sidebar( $_args['id'] ) ) {
$_args['id'] = $args['id'] . '-' . $n++;
}
} else {
$n = count( $wp_registered_sidebars );
do {
$_args['id'] = 'sidebar-' . ++$n;
} while ( is_registered_sidebar( $_args['id'] ) );
}
register_sidebar( $_args );
}
}
/**
* Builds the definition for a single sidebar and returns the ID.
*
* Accepts either a string or an array and then parses that against a set
* of default arguments for the new sidebar. WordPress will automatically
* generate a sidebar ID and name based on the current number of registered
* sidebars if those arguments are not included.
*
* When allowing for automatic generation of the name and ID parameters, keep
* in mind that the incrementor for your sidebar can change over time depending
* on what other plugins and themes are installed.
*
* If theme support for 'widgets' has not yet been added when this function is
* called, it will be automatically enabled through the use of add_theme_support().
*
* @since 2.2.0
* @since 5.6.0 Added the `before_sidebar` and `after_sidebar` arguments.
* @since 5.9.0 Added the `show_in_rest` argument.
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param array|string $args {
* Optional. Array or string of arguments for the sidebar being registered.
*
* @type string $name The name or title of the sidebar displayed in the Widgets
* interface. Default 'Sidebar $instance'.
* @type string $id The unique identifier by which the sidebar will be called.
* Default 'sidebar-$instance'.
* @type string $description Description of the sidebar, displayed in the Widgets interface.
* Default empty string.
* @type string $class Extra CSS class to assign to the sidebar in the Widgets interface.
* Default empty.
* @type string $before_widget HTML content to prepend to each widget's HTML output when assigned
* to this sidebar. Receives the widget's ID attribute as `%1$s`
* and class name as `%2$s`. Default is an opening list item element.
* @type string $after_widget HTML content to append to each widget's HTML output when assigned
* to this sidebar. Default is a closing list item element.
* @type string $before_title HTML content to prepend to the sidebar title when displayed.
* Default is an opening h2 element.
* @type string $after_title HTML content to append to the sidebar title when displayed.
* Default is a closing h2 element.
* @type string $before_sidebar HTML content to prepend to the sidebar when displayed.
* Receives the `$id` argument as `%1$s` and `$class` as `%2$s`.
* Outputs after the {@see 'dynamic_sidebar_before'} action.
* Default empty string.
* @type string $after_sidebar HTML content to append to the sidebar when displayed.
* Outputs before the {@see 'dynamic_sidebar_after'} action.
* Default empty string.
* @type bool $show_in_rest Whether to show this sidebar publicly in the REST API.
* Defaults to only showing the sidebar to administrator users.
* }
* @return string Sidebar ID added to $wp_registered_sidebars global.
*/
function register_sidebar( $args = array() ) {
global $wp_registered_sidebars;
$i = count( $wp_registered_sidebars ) + 1;
$id_is_empty = empty( $args['id'] );
$defaults = array(
/* translators: %d: Sidebar number. */
'name' => sprintf( __( 'Sidebar %d' ), $i ),
'id' => "sidebar-$i",
'description' => '',
'class' => '',
'before_widget' => '<li id="%1$s" class="widget %2$s">',
'after_widget' => "</li>\n",
'before_title' => '<h2 class="widgettitle">',
'after_title' => "</h2>\n",
'before_sidebar' => '',
'after_sidebar' => '',
'show_in_rest' => false,
);
/**
* Filters the sidebar default arguments.
*
* @since 5.3.0
*
* @see register_sidebar()
*
* @param array $defaults The default sidebar arguments.
*/
$sidebar = wp_parse_args( $args, apply_filters( 'register_sidebar_defaults', $defaults ) );
if ( $id_is_empty ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: The 'id' argument, 2: Sidebar name, 3: Recommended 'id' value. */
__( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ),
'<code>id</code>',
$sidebar['name'],
$sidebar['id']
),
'4.2.0'
);
}
$wp_registered_sidebars[ $sidebar['id'] ] = $sidebar;
add_theme_support( 'widgets' );
/**
* Fires once a sidebar has been registered.
*
* @since 3.0.0
*
* @param array $sidebar Parsed arguments for the registered sidebar.
*/
do_action( 'register_sidebar', $sidebar );
return $sidebar['id'];
}
/**
* Removes a sidebar from the list.
*
* @since 2.2.0
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param string|int $sidebar_id The ID of the sidebar when it was registered.
*/
function unregister_sidebar( $sidebar_id ) {
global $wp_registered_sidebars;
unset( $wp_registered_sidebars[ $sidebar_id ] );
}
/**
* Checks if a sidebar is registered.
*
* @since 4.4.0
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param string|int $sidebar_id The ID of the sidebar when it was registered.
* @return bool True if the sidebar is registered, false otherwise.
*/
function is_registered_sidebar( $sidebar_id ) {
global $wp_registered_sidebars;
return isset( $wp_registered_sidebars[ $sidebar_id ] );
}
/**
* Registers an instance of a widget.
*
* The default widget option is 'classname' that can be overridden.
*
* The function can also be used to un-register widgets when `$output_callback`
* parameter is an empty string.
*
* @since 2.2.0
* @since 5.3.0 Formalized the existing and already documented `...$params` parameter
* by adding it to the function signature.
* @since 5.8.0 Added show_instance_in_rest option.
*
* @global array $wp_registered_widgets Uses stored registered widgets.
* @global array $wp_registered_widget_controls Stores the registered widget controls (options).
* @global array $wp_registered_widget_updates The registered widget updates.
* @global array $_wp_deprecated_widgets_callbacks
*
* @param int|string $id Widget ID.
* @param string $name Widget display title.
* @param callable $output_callback Run when widget is called.
* @param array $options {
* Optional. An array of supplementary widget options for the instance.
*
* @type string $classname Class name for the widget's HTML container. Default is a shortened
* version of the output callback name.
* @type string $description Widget description for display in the widget administration
* panel and/or theme.
* @type bool $show_instance_in_rest Whether to show the widget's instance settings in the REST API.
* Only available for WP_Widget based widgets.
* }
* @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
*/
function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array(), ...$params ) {
global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
$id = strtolower( $id );
if ( empty( $output_callback ) ) {
unset( $wp_registered_widgets[ $id ] );
return;
}
$id_base = _get_widget_id_base( $id );
if ( in_array( $output_callback, $_wp_deprecated_widgets_callbacks, true ) && ! is_callable( $output_callback ) ) {
unset( $wp_registered_widget_controls[ $id ] );
unset( $wp_registered_widget_updates[ $id_base ] );
return;
}
$defaults = array( 'classname' => $output_callback );
$options = wp_parse_args( $options, $defaults );
$widget = array(
'name' => $name,
'id' => $id,
'callback' => $output_callback,
'params' => $params,
);
$widget = array_merge( $widget, $options );
if ( is_callable( $output_callback ) && ( ! isset( $wp_registered_widgets[ $id ] ) || did_action( 'widgets_init' ) ) ) {
/**
* Fires once for each registered widget.
*
* @since 3.0.0
*
* @param array $widget An array of default widget arguments.
*/
do_action( 'wp_register_sidebar_widget', $widget );
$wp_registered_widgets[ $id ] = $widget;
}
}
/**
* Retrieves description for widget.
*
* When registering widgets, the options can also include 'description' that
* describes the widget for display on the widget administration panel or
* in the theme.
*
* @since 2.5.0
*
* @global array $wp_registered_widgets The registered widgets.
*
* @param int|string $id Widget ID.
* @return string|void Widget description, if available.
*/
function wp_widget_description( $id ) {
if ( ! is_scalar( $id ) ) {
return;
}
global $wp_registered_widgets;
if ( isset( $wp_registered_widgets[ $id ]['description'] ) ) {
return esc_html( $wp_registered_widgets[ $id ]['description'] );
}
}
/**
* Retrieves description for a sidebar.
*
* When registering sidebars a 'description' parameter can be included that
* describes the sidebar for display on the widget administration panel.
*
* @since 2.9.0
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param string $id sidebar ID.
* @return string|void Sidebar description, if available.
*/
function wp_sidebar_description( $id ) {
if ( ! is_scalar( $id ) ) {
return;
}
global $wp_registered_sidebars;
if ( isset( $wp_registered_sidebars[ $id ]['description'] ) ) {
return wp_kses( $wp_registered_sidebars[ $id ]['description'], 'sidebar_description' );
}
}
/**
* Remove widget from sidebar.
*
* @since 2.2.0
*
* @param int|string $id Widget ID.
*/
function wp_unregister_sidebar_widget( $id ) {
/**
* Fires just before a widget is removed from a sidebar.
*
* @since 3.0.0
*
* @param int|string $id The widget ID.
*/
do_action( 'wp_unregister_sidebar_widget', $id );
wp_register_sidebar_widget( $id, '', '' );
wp_unregister_widget_control( $id );
}
/**
* Registers widget control callback for customizing options.
*
* @since 2.2.0
* @since 5.3.0 Formalized the existing and already documented `...$params` parameter
* by adding it to the function signature.
*
* @global array $wp_registered_widget_controls The registered widget controls.
* @global array $wp_registered_widget_updates The registered widget updates.
* @global array $wp_registered_widgets The registered widgets.
* @global array $_wp_deprecated_widgets_callbacks
*
* @param int|string $id Sidebar ID.
* @param string $name Sidebar display name.
* @param callable $control_callback Run when sidebar is displayed.
* @param array $options {
* Optional. Array or string of control options. Default empty array.
*
* @type int $height Never used. Default 200.
* @type int $width Width of the fully expanded control form (but try hard to use the default width).
* Default 250.
* @type int|string $id_base Required for multi-widgets, i.e widgets that allow multiple instances such as the
* text widget. The widget ID will end up looking like `{$id_base}-{$unique_number}`.
* }
* @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
*/
function wp_register_widget_control( $id, $name, $control_callback, $options = array(), ...$params ) {
global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
$id = strtolower( $id );
$id_base = _get_widget_id_base( $id );
if ( empty( $control_callback ) ) {
unset( $wp_registered_widget_controls[ $id ] );
unset( $wp_registered_widget_updates[ $id_base ] );
return;
}
if ( in_array( $control_callback, $_wp_deprecated_widgets_callbacks, true ) && ! is_callable( $control_callback ) ) {
unset( $wp_registered_widgets[ $id ] );
return;
}
if ( isset( $wp_registered_widget_controls[ $id ] ) && ! did_action( 'widgets_init' ) ) {
return;
}
$defaults = array(
'width' => 250,
'height' => 200,
); // Height is never used.
$options = wp_parse_args( $options, $defaults );
$options['width'] = (int) $options['width'];
$options['height'] = (int) $options['height'];
$widget = array(
'name' => $name,
'id' => $id,
'callback' => $control_callback,
'params' => $params,
);
$widget = array_merge( $widget, $options );
$wp_registered_widget_controls[ $id ] = $widget;
if ( isset( $wp_registered_widget_updates[ $id_base ] ) ) {
return;
}
if ( isset( $widget['params'][0]['number'] ) ) {
$widget['params'][0]['number'] = -1;
}
unset( $widget['width'], $widget['height'], $widget['name'], $widget['id'] );
$wp_registered_widget_updates[ $id_base ] = $widget;
}
/**
* Registers the update callback for a widget.
*
* @since 2.8.0
* @since 5.3.0 Formalized the existing and already documented `...$params` parameter
* by adding it to the function signature.
*
* @global array $wp_registered_widget_updates The registered widget updates.
*
* @param string $id_base The base ID of a widget created by extending WP_Widget.
* @param callable $update_callback Update callback method for the widget.
* @param array $options Optional. Widget control options. See wp_register_widget_control().
* Default empty array.
* @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
*/
function _register_widget_update_callback( $id_base, $update_callback, $options = array(), ...$params ) {
global $wp_registered_widget_updates;
if ( isset( $wp_registered_widget_updates[ $id_base ] ) ) {
if ( empty( $update_callback ) ) {
unset( $wp_registered_widget_updates[ $id_base ] );
}
return;
}
$widget = array(
'callback' => $update_callback,
'params' => $params,
);
$widget = array_merge( $widget, $options );
$wp_registered_widget_updates[ $id_base ] = $widget;
}
/**
* Registers the form callback for a widget.
*
* @since 2.8.0
* @since 5.3.0 Formalized the existing and already documented `...$params` parameter
* by adding it to the function signature.
*
* @global array $wp_registered_widget_controls The registered widget controls.
*
* @param int|string $id Widget ID.
* @param string $name Name attribute for the widget.
* @param callable $form_callback Form callback.
* @param array $options Optional. Widget control options. See wp_register_widget_control().
* Default empty array.
* @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
*/
function _register_widget_form_callback( $id, $name, $form_callback, $options = array(), ...$params ) {
global $wp_registered_widget_controls;
$id = strtolower( $id );
if ( empty( $form_callback ) ) {
unset( $wp_registered_widget_controls[ $id ] );
return;
}
if ( isset( $wp_registered_widget_controls[ $id ] ) && ! did_action( 'widgets_init' ) ) {
return;
}
$defaults = array(
'width' => 250,
'height' => 200,
);
$options = wp_parse_args( $options, $defaults );
$options['width'] = (int) $options['width'];
$options['height'] = (int) $options['height'];
$widget = array(
'name' => $name,
'id' => $id,
'callback' => $form_callback,
'params' => $params,
);
$widget = array_merge( $widget, $options );
$wp_registered_widget_controls[ $id ] = $widget;
}
/**
* Removes control callback for widget.
*
* @since 2.2.0
*
* @param int|string $id Widget ID.
*/
function wp_unregister_widget_control( $id ) {
wp_register_widget_control( $id, '', '' );
}
/**
* Displays dynamic sidebar.
*
* By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
* 'name' parameter for its registered sidebars you can pass an ID or name as the $index parameter.
* Otherwise, you can pass in a numerical index to display the sidebar at that index.
*
* @since 2.2.0
*
* @global array $wp_registered_sidebars The registered sidebars.
* @global array $wp_registered_widgets The registered widgets.
*
* @param int|string $index Optional. Index, name or ID of dynamic sidebar. Default 1.
* @return bool True, if widget sidebar was found and called. False if not found or not called.
*/
function dynamic_sidebar( $index = 1 ) {
global $wp_registered_sidebars, $wp_registered_widgets;
if ( is_int( $index ) ) {
$index = "sidebar-$index";
} else {
$index = sanitize_title( $index );
foreach ( (array) $wp_registered_sidebars as $key => $value ) {
if ( sanitize_title( $value['name'] ) === $index ) {
$index = $key;
break;
}
}
}
$sidebars_widgets = wp_get_sidebars_widgets();
if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
/** This action is documented in wp-includes/widget.php */
do_action( 'dynamic_sidebar_before', $index, false );
/** This action is documented in wp-includes/widget.php */
do_action( 'dynamic_sidebar_after', $index, false );
/** This filter is documented in wp-includes/widget.php */
return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
}
$sidebar = $wp_registered_sidebars[ $index ];
$sidebar['before_sidebar'] = sprintf( $sidebar['before_sidebar'], $sidebar['id'], $sidebar['class'] );
/**
* Fires before widgets are rendered in a dynamic sidebar.
*
* Note: The action also fires for empty sidebars, and on both the front end
* and back end, including the Inactive Widgets sidebar on the Widgets screen.
*
* @since 3.9.0
*
* @param int|string $index Index, name, or ID of the dynamic sidebar.
* @param bool $has_widgets Whether the sidebar is populated with widgets.
* Default true.
*/
do_action( 'dynamic_sidebar_before', $index, true );
if ( ! is_admin() && ! empty( $sidebar['before_sidebar'] ) ) {
echo $sidebar['before_sidebar'];
}
$did_one = false;
foreach ( (array) $sidebars_widgets[ $index ] as $id ) {
if ( ! isset( $wp_registered_widgets[ $id ] ) ) {
continue;
}
$params = array_merge(
array(
array_merge(
$sidebar,
array(
'widget_id' => $id,
'widget_name' => $wp_registered_widgets[ $id ]['name'],
)
),
),
(array) $wp_registered_widgets[ $id ]['params']
);
// Substitute HTML `id` and `class` attributes into `before_widget`.
$classname_ = '';
foreach ( (array) $wp_registered_widgets[ $id ]['classname'] as $cn ) {
if ( is_string( $cn ) ) {
$classname_ .= '_' . $cn;
} elseif ( is_object( $cn ) ) {
$classname_ .= '_' . get_class( $cn );
}
}
$classname_ = ltrim( $classname_, '_' );
$params[0]['before_widget'] = sprintf(
$params[0]['before_widget'],
str_replace( '\\', '_', $id ),
$classname_
);
/**
* Filters the parameters passed to a widget's display callback.
*
* Note: The filter is evaluated on both the front end and back end,
* including for the Inactive Widgets sidebar on the Widgets screen.
*
* @since 2.5.0
*
* @see register_sidebar()
*
* @param array $params {
* @type array $args {
* An array of widget display arguments.
*
* @type string $name Name of the sidebar the widget is assigned to.
* @type string $id ID of the sidebar the widget is assigned to.
* @type string $description The sidebar description.
* @type string $class CSS class applied to the sidebar container.
* @type string $before_widget HTML markup to prepend to each widget in the sidebar.
* @type string $after_widget HTML markup to append to each widget in the sidebar.
* @type string $before_title HTML markup to prepend to the widget title when displayed.
* @type string $after_title HTML markup to append to the widget title when displayed.
* @type string $widget_id ID of the widget.
* @type string $widget_name Name of the widget.
* }
* @type array $widget_args {
* An array of multi-widget arguments.
*
* @type int $number Number increment used for multiples of the same widget.
* }
* }
*/
$params = apply_filters( 'dynamic_sidebar_params', $params );
$callback = $wp_registered_widgets[ $id ]['callback'];
/**
* Fires before a widget's display callback is called.
*
* Note: The action fires on both the front end and back end, including
* for widgets in the Inactive Widgets sidebar on the Widgets screen.
*
* The action is not fired for empty sidebars.
*
* @since 3.0.0
*
* @param array $widget {
* An associative array of widget arguments.
*
* @type string $name Name of the widget.
* @type string $id Widget ID.
* @type callable $callback When the hook is fired on the front end, `$callback` is an array
* containing the widget object. Fired on the back end, `$callback`
* is 'wp_widget_control', see `$_callback`.
* @type array $params An associative array of multi-widget arguments.
* @type string $classname CSS class applied to the widget container.
* @type string $description The widget description.
* @type array $_callback When the hook is fired on the back end, `$_callback` is populated
* with an array containing the widget object, see `$callback`.
* }
*/
do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
if ( is_callable( $callback ) ) {
call_user_func_array( $callback, $params );
$did_one = true;
}
}
if ( ! is_admin() && ! empty( $sidebar['after_sidebar'] ) ) {
echo $sidebar['after_sidebar'];
}
/**
* Fires after widgets are rendered in a dynamic sidebar.
*
* Note: The action also fires for empty sidebars, and on both the front end
* and back end, including the Inactive Widgets sidebar on the Widgets screen.
*
* @since 3.9.0
*
* @param int|string $index Index, name, or ID of the dynamic sidebar.
* @param bool $has_widgets Whether the sidebar is populated with widgets.
* Default true.
*/
do_action( 'dynamic_sidebar_after', $index, true );
/**
* Filters whether a sidebar has widgets.
*
* Note: The filter is also evaluated for empty sidebars, and on both the front end
* and back end, including the Inactive Widgets sidebar on the Widgets screen.
*
* @since 3.9.0
*
* @param bool $did_one Whether at least one widget was rendered in the sidebar.
* Default false.
* @param int|string $index Index, name, or ID of the dynamic sidebar.
*/
return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
}
/**
* Determines whether a given widget is displayed on the front end.
*
* Either $callback or $id_base can be used.
* $id_base is the first argument when extending WP_Widget class.
* Without the optional $widget_id parameter, returns the ID of the first sidebar
* in which the first instance of the widget with the given callback or $id_base is found.
* With the $widget_id parameter, returns the ID of the sidebar where
* the widget with that callback/$id_base AND that ID is found.
*
* NOTE: $widget_id and $id_base are the same for single widgets. To be effective
* this function has to run after widgets have initialized, at action {@see 'init'} or later.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 2.2.0
*
* @global array $wp_registered_widgets The registered widgets.
*
* @param callable|false $callback Optional. Widget callback to check. Default false.
* @param string|false $widget_id Optional. Widget ID. Optional, but needed for checking.
* Default false.
* @param string|false $id_base Optional. The base ID of a widget created by extending WP_Widget.
* Default false.
* @param bool $skip_inactive Optional. Whether to check in 'wp_inactive_widgets'.
* Default true.
* @return string|false ID of the sidebar in which the widget is active,
* false if the widget is not active.
*/
function is_active_widget( $callback = false, $widget_id = false, $id_base = false, $skip_inactive = true ) {
global $wp_registered_widgets;
$sidebars_widgets = wp_get_sidebars_widgets();
if ( is_array( $sidebars_widgets ) ) {
foreach ( $sidebars_widgets as $sidebar => $widgets ) {
if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || str_starts_with( $sidebar, 'orphaned_widgets' ) ) ) {
continue;
}
if ( is_array( $widgets ) ) {
foreach ( $widgets as $widget ) {
if ( ( $callback && isset( $wp_registered_widgets[ $widget ]['callback'] ) && $wp_registered_widgets[ $widget ]['callback'] === $callback ) || ( $id_base && _get_widget_id_base( $widget ) === $id_base ) ) {
if ( ! $widget_id || $widget_id === $wp_registered_widgets[ $widget ]['id'] ) {
return $sidebar;
}
}
}
}
}
}
return false;
}
/**
* Determines whether the dynamic sidebar is enabled and used by the theme.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 2.2.0
*
* @global array $wp_registered_widgets The registered widgets.
* @global array $wp_registered_sidebars The registered sidebars.
*
* @return bool True if using widgets, false otherwise.
*/
function is_dynamic_sidebar() {
global $wp_registered_widgets, $wp_registered_sidebars;
$sidebars_widgets = get_option( 'sidebars_widgets' );
foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
if ( ! empty( $sidebars_widgets[ $index ] ) ) {
foreach ( (array) $sidebars_widgets[ $index ] as $widget ) {
if ( array_key_exists( $widget, $wp_registered_widgets ) ) {
return true;
}
}
}
}
return false;
}
/**
* Determines whether a sidebar contains widgets.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 2.8.0
*
* @param string|int $index Sidebar name, id or number to check.
* @return bool True if the sidebar has widgets, false otherwise.
*/
function is_active_sidebar( $index ) {
$index = ( is_int( $index ) ) ? "sidebar-$index" : sanitize_title( $index );
$sidebars_widgets = wp_get_sidebars_widgets();
$is_active_sidebar = ! empty( $sidebars_widgets[ $index ] );
/**
* Filters whether a dynamic sidebar is considered "active".
*
* @since 3.9.0
*
* @param bool $is_active_sidebar Whether or not the sidebar should be considered "active".
* In other words, whether the sidebar contains any widgets.
* @param int|string $index Index, name, or ID of the dynamic sidebar.
*/
return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
}
//
// Internal Functions.
//
/**
* Retrieves the full list of sidebars and their widget instance IDs.
*
* Will upgrade sidebar widget list, if needed. Will also save updated list, if
* needed.
*
* @since 2.2.0
* @access private
*
* @global array $_wp_sidebars_widgets
* @global array $sidebars_widgets
*
* @param bool $deprecated Not used (argument deprecated).
* @return array Upgraded list of widgets to version 3 array format when called from the admin.
*/
function wp_get_sidebars_widgets( $deprecated = true ) {
if ( true !== $deprecated ) {
_deprecated_argument( __FUNCTION__, '2.8.1' );
}
global $_wp_sidebars_widgets, $sidebars_widgets;
/*
* If loading from front page, consult $_wp_sidebars_widgets rather than options
* to see if wp_convert_widget_settings() has made manipulations in memory.
*/
if ( ! is_admin() ) {
if ( empty( $_wp_sidebars_widgets ) ) {
$_wp_sidebars_widgets = get_option( 'sidebars_widgets', array() );
}
$sidebars_widgets = $_wp_sidebars_widgets;
} else {
$sidebars_widgets = get_option( 'sidebars_widgets', array() );
}
if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) {
unset( $sidebars_widgets['array_version'] );
}
/**
* Filters the list of sidebars and their widgets.
*
* @since 2.7.0
*
* @param array $sidebars_widgets An associative array of sidebars and their widgets.
*/
return apply_filters( 'sidebars_widgets', $sidebars_widgets );
}
/**
* Retrieves the registered sidebar with the given ID.
*
* @since 5.9.0
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param string $id The sidebar ID.
* @return array|null The discovered sidebar, or null if it is not registered.
*/
function wp_get_sidebar( $id ) {
global $wp_registered_sidebars;
foreach ( (array) $wp_registered_sidebars as $sidebar ) {
if ( $sidebar['id'] === $id ) {
return $sidebar;
}
}
if ( 'wp_inactive_widgets' === $id ) {
return array(
'id' => 'wp_inactive_widgets',
'name' => __( 'Inactive widgets' ),
);
}
return null;
}
/**
* Sets the sidebar widget option to update sidebars.
*
* @since 2.2.0
* @access private
*
* @global array $_wp_sidebars_widgets
* @param array $sidebars_widgets Sidebar widgets and their settings.
*/
function wp_set_sidebars_widgets( $sidebars_widgets ) {
global $_wp_sidebars_widgets;
// Clear cached value used in wp_get_sidebars_widgets().
$_wp_sidebars_widgets = null;
if ( ! isset( $sidebars_widgets['array_version'] ) ) {
$sidebars_widgets['array_version'] = 3;
}
update_option( 'sidebars_widgets', $sidebars_widgets );
}
/**
* Retrieves default registered sidebars list.
*
* @since 2.2.0
* @access private
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @return array
*/
function wp_get_widget_defaults() {
global $wp_registered_sidebars;
$defaults = array();
foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
$defaults[ $index ] = array();
}
return $defaults;
}
/**
* Converts the widget settings from single to multi-widget format.
*
* @since 2.8.0
*
* @global array $_wp_sidebars_widgets
*
* @param string $base_name Root ID for all widgets of this type.
* @param string $option_name Option name for this widget type.
* @param array $settings The array of widget instance settings.
* @return array The array of widget settings converted to multi-widget format.
*/
function wp_convert_widget_settings( $base_name, $option_name, $settings ) {
// This test may need expanding.
$single = false;
$changed = false;
if ( empty( $settings ) ) {
$single = true;
} else {
foreach ( array_keys( $settings ) as $number ) {
if ( 'number' === $number ) {
continue;
}
if ( ! is_numeric( $number ) ) {
$single = true;
break;
}
}
}
if ( $single ) {
$settings = array( 2 => $settings );
// If loading from the front page, update sidebar in memory but don't save to options.
if ( is_admin() ) {
$sidebars_widgets = get_option( 'sidebars_widgets' );
} else {
if ( empty( $GLOBALS['_wp_sidebars_widgets'] ) ) {
$GLOBALS['_wp_sidebars_widgets'] = get_option( 'sidebars_widgets', array() );
}
$sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
}
foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
if ( is_array( $sidebar ) ) {
foreach ( $sidebar as $i => $name ) {
if ( $base_name === $name ) {
$sidebars_widgets[ $index ][ $i ] = "$name-2";
$changed = true;
break 2;
}
}
}
}
if ( is_admin() && $changed ) {
update_option( 'sidebars_widgets', $sidebars_widgets );
}
}
$settings['_multiwidget'] = 1;
if ( is_admin() ) {
update_option( $option_name, $settings );
}
return $settings;
}
/**
* Outputs an arbitrary widget as a template tag.
*
* @since 2.8.0
*
* @global WP_Widget_Factory $wp_widget_factory
*
* @param string $widget The widget's PHP class name (see class-wp-widget.php).
* @param array $instance Optional. The widget's instance settings. Default empty array.
* @param array $args {
* Optional. Array of arguments to configure the display of the widget.
*
* @type string $before_widget HTML content that will be prepended to the widget's HTML output.
* Default `<div class="widget %s">`, where `%s` is the widget's class name.
* @type string $after_widget HTML content that will be appended to the widget's HTML output.
* Default `</div>`.
* @type string $before_title HTML content that will be prepended to the widget's title when displayed.
* Default `<h2 class="widgettitle">`.
* @type string $after_title HTML content that will be appended to the widget's title when displayed.
* Default `</h2>`.
* }
*/
function the_widget( $widget, $instance = array(), $args = array() ) {
global $wp_widget_factory;
if ( ! isset( $wp_widget_factory->widgets[ $widget ] ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: register_widget() */
__( 'Widgets need to be registered using %s, before they can be displayed.' ),
'<code>register_widget()</code>'
),
'4.9.0'
);
return;
}
$widget_obj = $wp_widget_factory->widgets[ $widget ];
if ( ! ( $widget_obj instanceof WP_Widget ) ) {
return;
}
$default_args = array(
'before_widget' => '<div class="widget %s">',
'after_widget' => '</div>',
'before_title' => '<h2 class="widgettitle">',
'after_title' => '</h2>',
);
$args = wp_parse_args( $args, $default_args );
$args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
$instance = wp_parse_args( $instance );
/** This filter is documented in wp-includes/class-wp-widget.php */
$instance = apply_filters( 'widget_display_callback', $instance, $widget_obj, $args );
if ( false === $instance ) {
return;
}
/**
* Fires before rendering the requested widget.
*
* @since 3.0.0
*
* @param string $widget The widget's class name.
* @param array $instance The current widget instance's settings.
* @param array $args An array of the widget's sidebar arguments.
*/
do_action( 'the_widget', $widget, $instance, $args );
$widget_obj->_set( -1 );
$widget_obj->widget( $args, $instance );
}
/**
* Retrieves the widget ID base value.
*
* @since 2.8.0
*
* @param string $id Widget ID.
* @return string Widget ID base.
*/
function _get_widget_id_base( $id ) {
return preg_replace( '/-[0-9]+$/', '', $id );
}
/**
* Handles sidebars config after theme change.
*
* @access private
* @since 3.3.0
*
* @global array $sidebars_widgets
*/
function _wp_sidebars_changed() {
global $sidebars_widgets;
if ( ! is_array( $sidebars_widgets ) ) {
$sidebars_widgets = wp_get_sidebars_widgets();
}
retrieve_widgets( true );
}
/**
* Validates and remaps any "orphaned" widgets to wp_inactive_widgets sidebar,
* and saves the widget settings. This has to run at least on each theme change.
*
* For example, let's say theme A has a "footer" sidebar, and theme B doesn't have one.
* After switching from theme A to theme B, all the widgets previously assigned
* to the footer would be inaccessible. This function detects this scenario, and
* moves all the widgets previously assigned to the footer under wp_inactive_widgets.
*
* Despite the word "retrieve" in the name, this function actually updates the database
* and the global `$sidebars_widgets`. For that reason it should not be run on front end,
* unless the `$theme_changed` value is 'customize' (to bypass the database write).
*
* @since 2.8.0
*
* @global array $wp_registered_sidebars The registered sidebars.
* @global array $sidebars_widgets
* @global array $wp_registered_widgets The registered widgets.
*
* @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
* of 'customize' defers updates for the Customizer.
* @return array Updated sidebars widgets.
*/
function retrieve_widgets( $theme_changed = false ) {
global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
$registered_sidebars_keys = array_keys( $wp_registered_sidebars );
$registered_widgets_ids = array_keys( $wp_registered_widgets );
if ( ! is_array( get_theme_mod( 'sidebars_widgets' ) ) ) {
if ( empty( $sidebars_widgets ) ) {
return array();
}
unset( $sidebars_widgets['array_version'] );
$sidebars_widgets_keys = array_keys( $sidebars_widgets );
sort( $sidebars_widgets_keys );
sort( $registered_sidebars_keys );
if ( $sidebars_widgets_keys === $registered_sidebars_keys ) {
$sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
return $sidebars_widgets;
}
}
// Discard invalid, theme-specific widgets from sidebars.
$sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
$sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets );
// Find hidden/lost multi-widget instances.
$shown_widgets = array_merge( ...array_values( $sidebars_widgets ) );
$lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets );
foreach ( $lost_widgets as $key => $widget_id ) {
$number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id );
// Only keep active and default widgets.
if ( is_numeric( $number ) && (int) $number < 2 ) {
unset( $lost_widgets[ $key ] );
}
}
$sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] );
if ( 'customize' !== $theme_changed ) {
// Update the widgets settings in the database.
wp_set_sidebars_widgets( $sidebars_widgets );
}
return $sidebars_widgets;
}
/**
* Compares a list of sidebars with their widgets against an allowed list.
*
* @since 4.9.0
* @since 4.9.2 Always tries to restore widget assignments from previous data, not just if sidebars needed mapping.
*
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param array $existing_sidebars_widgets List of sidebars and their widget instance IDs.
* @return array Mapped sidebars widgets.
*/
function wp_map_sidebars_widgets( $existing_sidebars_widgets ) {
global $wp_registered_sidebars;
$new_sidebars_widgets = array(
'wp_inactive_widgets' => array(),
);
// Short-circuit if there are no sidebars to map.
if ( ! is_array( $existing_sidebars_widgets ) || empty( $existing_sidebars_widgets ) ) {
return $new_sidebars_widgets;
}
foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
if ( 'wp_inactive_widgets' === $sidebar || str_starts_with( $sidebar, 'orphaned_widgets' ) ) {
$new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], (array) $widgets );
unset( $existing_sidebars_widgets[ $sidebar ] );
}
}
// If old and new theme have just one sidebar, map it and we're done.
if ( 1 === count( $existing_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) {
$new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $existing_sidebars_widgets );
return $new_sidebars_widgets;
}
// Map locations with the same slug.
$existing_sidebars = array_keys( $existing_sidebars_widgets );
foreach ( $wp_registered_sidebars as $sidebar => $name ) {
if ( in_array( $sidebar, $existing_sidebars, true ) ) {
$new_sidebars_widgets[ $sidebar ] = $existing_sidebars_widgets[ $sidebar ];
unset( $existing_sidebars_widgets[ $sidebar ] );
} elseif ( ! array_key_exists( $sidebar, $new_sidebars_widgets ) ) {
$new_sidebars_widgets[ $sidebar ] = array();
}
}
// If there are more sidebars, try to map them.
if ( ! empty( $existing_sidebars_widgets ) ) {
/*
* If old and new theme both have sidebars that contain phrases
* from within the same group, make an educated guess and map it.
*/
$common_slug_groups = array(
array( 'sidebar', 'primary', 'main', 'right' ),
array( 'second', 'left' ),
array( 'sidebar-2', 'footer', 'bottom' ),
array( 'header', 'top' ),
);
// Go through each group...
foreach ( $common_slug_groups as $slug_group ) {
// ...and see if any of these slugs...
foreach ( $slug_group as $slug ) {
// ...and any of the new sidebars...
foreach ( $wp_registered_sidebars as $new_sidebar => $args ) {
// ...actually match!
if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) {
continue;
}
// Then see if any of the existing sidebars...
foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
// ...and any slug in the same group...
foreach ( $slug_group as $slug ) {
// ... have a match as well.
if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) {
continue;
}
// Make sure this sidebar wasn't mapped and removed previously.
if ( ! empty( $existing_sidebars_widgets[ $sidebar ] ) ) {
// We have a match that can be mapped!
$new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $existing_sidebars_widgets[ $sidebar ] );
// Remove the mapped sidebar so it can't be mapped again.
unset( $existing_sidebars_widgets[ $sidebar ] );
// Go back and check the next new sidebar.
continue 3;
}
} // End foreach ( $slug_group as $slug ).
} // End foreach ( $existing_sidebars_widgets as $sidebar => $widgets ).
} // End foreach ( $wp_registered_sidebars as $new_sidebar => $args ).
} // End foreach ( $slug_group as $slug ).
} // End foreach ( $common_slug_groups as $slug_group ).
}
// Move any left over widgets to inactive sidebar.
foreach ( $existing_sidebars_widgets as $widgets ) {
if ( is_array( $widgets ) && ! empty( $widgets ) ) {
$new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], $widgets );
}
}
// Sidebars_widgets settings from when this theme was previously active.
$old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
$old_sidebars_widgets = isset( $old_sidebars_widgets['data'] ) ? $old_sidebars_widgets['data'] : false;
if ( is_array( $old_sidebars_widgets ) ) {
// Remove empty sidebars, no need to map those.
$old_sidebars_widgets = array_filter( $old_sidebars_widgets );
// Only check sidebars that are empty or have not been mapped to yet.
foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
if ( array_key_exists( $new_sidebar, $old_sidebars_widgets ) && ! empty( $new_widgets ) ) {
unset( $old_sidebars_widgets[ $new_sidebar ] );
}
}
// Remove orphaned widgets, we're only interested in previously active sidebars.
foreach ( $old_sidebars_widgets as $sidebar => $widgets ) {
if ( str_starts_with( $sidebar, 'orphaned_widgets' ) ) {
unset( $old_sidebars_widgets[ $sidebar ] );
}
}
$old_sidebars_widgets = _wp_remove_unregistered_widgets( $old_sidebars_widgets );
if ( ! empty( $old_sidebars_widgets ) ) {
// Go through each remaining sidebar...
foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ) {
// ...and check every new sidebar...
foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
// ...for every widget we're trying to revive.
foreach ( $old_widgets as $key => $widget_id ) {
$active_key = array_search( $widget_id, $new_widgets, true );
// If the widget is used elsewhere...
if ( false !== $active_key ) {
// ...and that elsewhere is inactive widgets...
if ( 'wp_inactive_widgets' === $new_sidebar ) {
// ...remove it from there and keep the active version...
unset( $new_sidebars_widgets['wp_inactive_widgets'][ $active_key ] );
} else {
// ...otherwise remove it from the old sidebar and keep it in the new one.
unset( $old_sidebars_widgets[ $old_sidebar ][ $key ] );
}
} // End if ( $active_key ).
} // End foreach ( $old_widgets as $key => $widget_id ).
} // End foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ).
} // End foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ).
} // End if ( ! empty( $old_sidebars_widgets ) ).
// Restore widget settings from when theme was previously active.
$new_sidebars_widgets = array_merge( $new_sidebars_widgets, $old_sidebars_widgets );
}
return $new_sidebars_widgets;
}
/**
* Compares a list of sidebars with their widgets against an allowed list.
*
* @since 4.9.0
*
* @global array $wp_registered_widgets The registered widgets.
*
* @param array $sidebars_widgets List of sidebars and their widget instance IDs.
* @param array $allowed_widget_ids Optional. List of widget IDs to compare against. Default: Registered widgets.
* @return array Sidebars with allowed widgets.
*/
function _wp_remove_unregistered_widgets( $sidebars_widgets, $allowed_widget_ids = array() ) {
if ( empty( $allowed_widget_ids ) ) {
$allowed_widget_ids = array_keys( $GLOBALS['wp_registered_widgets'] );
}
foreach ( $sidebars_widgets as $sidebar => $widgets ) {
if ( is_array( $widgets ) ) {
$sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $allowed_widget_ids );
}
}
return $sidebars_widgets;
}
/**
* Displays the RSS entries in a list.
*
* @since 2.5.0
*
* @param string|array|object $rss RSS url.
* @param array $args Widget arguments.
*/
function wp_widget_rss_output( $rss, $args = array() ) {
if ( is_string( $rss ) ) {
$rss = fetch_feed( $rss );
} elseif ( is_array( $rss ) && isset( $rss['url'] ) ) {
$args = $rss;
$rss = fetch_feed( $rss['url'] );
} elseif ( ! is_object( $rss ) ) {
return;
}
if ( is_wp_error( $rss ) ) {
if ( is_admin() || current_user_can( 'manage_options' ) ) {
echo '<p><strong>' . __( 'RSS Error:' ) . '</strong> ' . esc_html( $rss->get_error_message() ) . '</p>';
}
return;
}
$default_args = array(
'show_author' => 0,
'show_date' => 0,
'show_summary' => 0,
'items' => 0,
);
$args = wp_parse_args( $args, $default_args );
$items = (int) $args['items'];
if ( $items < 1 || 20 < $items ) {
$items = 10;
}
$show_summary = (int) $args['show_summary'];
$show_author = (int) $args['show_author'];
$show_date = (int) $args['show_date'];
if ( ! $rss->get_item_quantity() ) {
echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
$rss->__destruct();
unset( $rss );
return;
}
echo '<ul>';
foreach ( $rss->get_items( 0, $items ) as $item ) {
$link = $item->get_link();
while ( ! empty( $link ) && stristr( $link, 'http' ) !== $link ) {
$link = substr( $link, 1 );
}
$link = esc_url( strip_tags( $link ) );
$title = esc_html( trim( strip_tags( $item->get_title() ) ) );
if ( empty( $title ) ) {
$title = __( 'Untitled' );
}
$desc = html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
$desc = esc_attr( wp_trim_words( $desc, 55, ' […]' ) );
$summary = '';
if ( $show_summary ) {
$summary = $desc;
// Change existing [...] to […].
if ( str_ends_with( $summary, '[...]' ) ) {
$summary = substr( $summary, 0, -5 ) . '[…]';
}
$summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
}
$date = '';
if ( $show_date ) {
$date = $item->get_date( 'U' );
if ( $date ) {
$date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
}
}
$author = '';
if ( $show_author ) {
$author = $item->get_author();
if ( is_object( $author ) ) {
$author = $author->get_name();
$author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
}
}
if ( '' === $link ) {
echo "<li>$title{$date}{$summary}{$author}</li>";
} elseif ( $show_summary ) {
echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
} else {
echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
}
}
echo '</ul>';
$rss->__destruct();
unset( $rss );
}
/**
* Displays RSS widget options form.
*
* The options for what fields are displayed for the RSS form are all booleans
* and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
* 'show_date'.
*
* @since 2.5.0
*
* @param array|string $args Values for input fields.
* @param array $inputs Override default display options.
*/
function wp_widget_rss_form( $args, $inputs = null ) {
$default_inputs = array(
'url' => true,
'title' => true,
'items' => true,
'show_summary' => true,
'show_author' => true,
'show_date' => true,
);
$inputs = wp_parse_args( $inputs, $default_inputs );
$args['title'] = isset( $args['title'] ) ? $args['title'] : '';
$args['url'] = isset( $args['url'] ) ? $args['url'] : '';
$args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
if ( $args['items'] < 1 || 20 < $args['items'] ) {
$args['items'] = 10;
}
$args['show_summary'] = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
$args['show_author'] = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
$args['show_date'] = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
if ( ! empty( $args['error'] ) ) {
echo '<p class="widget-error"><strong>' . __( 'RSS Error:' ) . '</strong> ' . esc_html( $args['error'] ) . '</p>';
}
$esc_number = esc_attr( $args['number'] );
if ( $inputs['url'] ) :
?>
<p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
<input class="widefat" id="rss-url-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][url]" type="text" value="<?php echo esc_url( $args['url'] ); ?>" /></p>
<?php endif; if ( $inputs['title'] ) : ?>
<p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
<input class="widefat" id="rss-title-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][title]" type="text" value="<?php echo esc_attr( $args['title'] ); ?>" /></p>
<?php endif; if ( $inputs['items'] ) : ?>
<p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
<select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
<?php
for ( $i = 1; $i <= 20; ++$i ) {
echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
}
?>
</select></p>
<?php endif; if ( $inputs['show_summary'] || $inputs['show_author'] || $inputs['show_date'] ) : ?>
<p>
<?php if ( $inputs['show_summary'] ) : ?>
<input id="rss-show-summary-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_summary]" type="checkbox" value="1" <?php checked( $args['show_summary'] ); ?> />
<label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label><br />
<?php endif; if ( $inputs['show_author'] ) : ?>
<input id="rss-show-author-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_author]" type="checkbox" value="1" <?php checked( $args['show_author'] ); ?> />
<label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label><br />
<?php endif; if ( $inputs['show_date'] ) : ?>
<input id="rss-show-date-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_date]" type="checkbox" value="1" <?php checked( $args['show_date'] ); ?> />
<label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label><br />
<?php endif; ?>
</p>
<?php
endif; // End of display options.
foreach ( array_keys( $default_inputs ) as $input ) :
if ( 'hidden' === $inputs[ $input ] ) :
$id = str_replace( '_', '-', $input );
?>
<input type="hidden" id="rss-<?php echo esc_attr( $id ); ?>-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][<?php echo esc_attr( $input ); ?>]" value="<?php echo esc_attr( $args[ $input ] ); ?>" />
<?php
endif;
endforeach;
}
/**
* Processes RSS feed widget data and optionally retrieve feed items.
*
* The feed widget can not have more than 20 items or it will reset back to the
* default, which is 10.
*
* The resulting array has the feed title, feed url, feed link (from channel),
* feed items, error (if any), and whether to show summary, author, and date.
* All respectively in the order of the array elements.
*
* @since 2.5.0
*
* @param array $widget_rss RSS widget feed data. Expects unescaped data.
* @param bool $check_feed Optional. Whether to check feed for errors. Default true.
* @return array
*/
function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
$items = (int) $widget_rss['items'];
if ( $items < 1 || 20 < $items ) {
$items = 10;
}
$url = sanitize_url( strip_tags( $widget_rss['url'] ) );
$title = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
$show_summary = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
$show_author = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] : 0;
$show_date = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
$error = false;
$link = '';
if ( $check_feed ) {
$rss = fetch_feed( $url );
if ( is_wp_error( $rss ) ) {
$error = $rss->get_error_message();
} else {
$link = esc_url( strip_tags( $rss->get_permalink() ) );
while ( stristr( $link, 'http' ) !== $link ) {
$link = substr( $link, 1 );
}
$rss->__destruct();
unset( $rss );
}
}
return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
}
/**
* Registers all of the default WordPress widgets on startup.
*
* Calls {@see 'widgets_init'} action after all of the WordPress widgets have been registered.
*
* @since 2.2.0
*/
function wp_widgets_init() {
if ( ! is_blog_installed() ) {
return;
}
register_widget( 'WP_Widget_Pages' );
register_widget( 'WP_Widget_Calendar' );
register_widget( 'WP_Widget_Archives' );
if ( get_option( 'link_manager_enabled' ) ) {
register_widget( 'WP_Widget_Links' );
}
register_widget( 'WP_Widget_Media_Audio' );
register_widget( 'WP_Widget_Media_Image' );
register_widget( 'WP_Widget_Media_Gallery' );
register_widget( 'WP_Widget_Media_Video' );
register_widget( 'WP_Widget_Meta' );
register_widget( 'WP_Widget_Search' );
register_widget( 'WP_Widget_Text' );
register_widget( 'WP_Widget_Categories' );
register_widget( 'WP_Widget_Recent_Posts' );
register_widget( 'WP_Widget_Recent_Comments' );
register_widget( 'WP_Widget_RSS' );
register_widget( 'WP_Widget_Tag_Cloud' );
register_widget( 'WP_Nav_Menu_Widget' );
register_widget( 'WP_Widget_Custom_HTML' );
register_widget( 'WP_Widget_Block' );
/**
* Fires after all default WordPress widgets have been registered.
*
* @since 2.2.0
*/
do_action( 'widgets_init' );
}
/**
* Enables the widgets block editor. This is hooked into 'after_setup_theme' so
* that the block editor is enabled by default but can be disabled by themes.
*
* @since 5.8.0
*
* @access private
*/
function wp_setup_widgets_block_editor() {
add_theme_support( 'widgets-block-editor' );
}
/**
* Determines whether or not to use the block editor to manage widgets.
* Defaults to true unless a theme has removed support for widgets-block-editor
* or a plugin has filtered the return value of this function.
*
* @since 5.8.0
*
* @return bool Whether to use the block editor to manage widgets.
*/
function wp_use_widgets_block_editor() {
/**
* Filters whether to use the block editor to manage widgets.
*
* @since 5.8.0
*
* @param bool $use_widgets_block_editor Whether to use the block editor to manage widgets.
*/
return apply_filters(
'use_widgets_block_editor',
get_theme_support( 'widgets-block-editor' )
);
}
/**
* Converts a widget ID into its id_base and number components.
*
* @since 5.8.0
*
* @param string $id Widget ID.
* @return array Array containing a widget's id_base and number components.
*/
function wp_parse_widget_id( $id ) {
$parsed = array();
if ( preg_match( '/^(.+)-(\d+)$/', $id, $matches ) ) {
$parsed['id_base'] = $matches[1];
$parsed['number'] = (int) $matches[2];
} else {
// Likely an old single widget.
$parsed['id_base'] = $id;
}
return $parsed;
}
/**
* Finds the sidebar that a given widget belongs to.
*
* @since 5.8.0
*
* @param string $widget_id The widget ID to look for.
* @return string|null The found sidebar's ID, or null if it was not found.
*/
function wp_find_widgets_sidebar( $widget_id ) {
foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) {
foreach ( $widget_ids as $maybe_widget_id ) {
if ( $maybe_widget_id === $widget_id ) {
return (string) $sidebar_id;
}
}
}
return null;
}
/**
* Assigns a widget to the given sidebar.
*
* @since 5.8.0
*
* @param string $widget_id The widget ID to assign.
* @param string $sidebar_id The sidebar ID to assign to. If empty, the widget won't be added to any sidebar.
*/
function wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ) {
$sidebars = wp_get_sidebars_widgets();
foreach ( $sidebars as $maybe_sidebar_id => $widgets ) {
foreach ( $widgets as $i => $maybe_widget_id ) {
if ( $widget_id === $maybe_widget_id && $sidebar_id !== $maybe_sidebar_id ) {
unset( $sidebars[ $maybe_sidebar_id ][ $i ] );
// We could technically break 2 here, but continue looping in case the ID is duplicated.
continue 2;
}
}
}
if ( $sidebar_id ) {
$sidebars[ $sidebar_id ][] = $widget_id;
}
wp_set_sidebars_widgets( $sidebars );
}
/**
* Calls the render callback of a widget and returns the output.
*
* @since 5.8.0
*
* @global array $wp_registered_widgets The registered widgets.
* @global array $wp_registered_sidebars The registered sidebars.
*
* @param string $widget_id Widget ID.
* @param string $sidebar_id Sidebar ID.
* @return string
*/
function wp_render_widget( $widget_id, $sidebar_id ) {
global $wp_registered_widgets, $wp_registered_sidebars;
if ( ! isset( $wp_registered_widgets[ $widget_id ] ) ) {
return '';
}
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
$sidebar = $wp_registered_sidebars[ $sidebar_id ];
} elseif ( 'wp_inactive_widgets' === $sidebar_id ) {
$sidebar = array();
} else {
return '';
}
$params = array_merge(
array(
array_merge(
$sidebar,
array(
'widget_id' => $widget_id,
'widget_name' => $wp_registered_widgets[ $widget_id ]['name'],
)
),
),
(array) $wp_registered_widgets[ $widget_id ]['params']
);
// Substitute HTML `id` and `class` attributes into `before_widget`.
$classname_ = '';
foreach ( (array) $wp_registered_widgets[ $widget_id ]['classname'] as $cn ) {
if ( is_string( $cn ) ) {
$classname_ .= '_' . $cn;
} elseif ( is_object( $cn ) ) {
$classname_ .= '_' . get_class( $cn );
}
}
$classname_ = ltrim( $classname_, '_' );
$params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $widget_id, $classname_ );
/** This filter is documented in wp-includes/widgets.php */
$params = apply_filters( 'dynamic_sidebar_params', $params );
$callback = $wp_registered_widgets[ $widget_id ]['callback'];
ob_start();
/** This filter is documented in wp-includes/widgets.php */
do_action( 'dynamic_sidebar', $wp_registered_widgets[ $widget_id ] );
if ( is_callable( $callback ) ) {
call_user_func_array( $callback, $params );
}
return ob_get_clean();
}
/**
* Calls the control callback of a widget and returns the output.
*
* @since 5.8.0
*
* @global array $wp_registered_widget_controls The registered widget controls.
*
* @param string $id Widget ID.
* @return string|null
*/
function wp_render_widget_control( $id ) {
global $wp_registered_widget_controls;
if ( ! isset( $wp_registered_widget_controls[ $id ]['callback'] ) ) {
return null;
}
$callback = $wp_registered_widget_controls[ $id ]['callback'];
$params = $wp_registered_widget_controls[ $id ]['params'];
ob_start();
if ( is_callable( $callback ) ) {
call_user_func_array( $callback, $params );
}
return ob_get_clean();
}
/**
* Displays a _doing_it_wrong() message for conflicting widget editor scripts.
*
* The 'wp-editor' script module is exposed as window.wp.editor. This overrides
* the legacy TinyMCE editor module which is required by the widgets editor.
* Because of that conflict, these two shouldn't be enqueued together.
* See https://core.trac.wordpress.org/ticket/53569.
*
* There is also another conflict related to styles where the block widgets
* editor is hidden if a block enqueues 'wp-edit-post' stylesheet.
* See https://core.trac.wordpress.org/ticket/53569.
*
* @since 5.8.0
* @access private
*
* @global WP_Scripts $wp_scripts
* @global WP_Styles $wp_styles
*/
function wp_check_widget_editor_deps() {
global $wp_scripts, $wp_styles;
if (
$wp_scripts->query( 'wp-edit-widgets', 'enqueued' ) ||
$wp_scripts->query( 'wp-customize-widgets', 'enqueued' )
) {
if ( $wp_scripts->query( 'wp-editor', 'enqueued' ) ) {
_doing_it_wrong(
'wp_enqueue_script()',
sprintf(
/* translators: 1: 'wp-editor', 2: 'wp-edit-widgets', 3: 'wp-customize-widgets'. */
__( '"%1$s" script should not be enqueued together with the new widgets editor (%2$s or %3$s).' ),
'wp-editor',
'wp-edit-widgets',
'wp-customize-widgets'
),
'5.8.0'
);
}
if ( $wp_styles->query( 'wp-edit-post', 'enqueued' ) ) {
_doing_it_wrong(
'wp_enqueue_style()',
sprintf(
/* translators: 1: 'wp-edit-post', 2: 'wp-edit-widgets', 3: 'wp-customize-widgets'. */
__( '"%1$s" style should not be enqueued together with the new widgets editor (%2$s or %3$s).' ),
'wp-edit-post',
'wp-edit-widgets',
'wp-customize-widgets'
),
'5.8.0'
);
}
}
}
/**
* Registers the previous theme's sidebars for the block themes.
*
* @since 6.2.0
* @access private
*
* @global array $wp_registered_sidebars The registered sidebars.
*/
function _wp_block_theme_register_classic_sidebars() {
global $wp_registered_sidebars;
if ( ! wp_is_block_theme() ) {
return;
}
$classic_sidebars = get_theme_mod( 'wp_classic_sidebars' );
if ( empty( $classic_sidebars ) ) {
return;
}
// Don't use `register_sidebar` since it will enable the `widgets` support for a theme.
foreach ( $classic_sidebars as $sidebar ) {
$wp_registered_sidebars[ $sidebar['id'] ] = $sidebar;
}
}
<?php
/**
* Diff API: WP_Text_Diff_Renderer_inline class
*
* @package WordPress
* @subpackage Diff
* @since 4.7.0
*/
/**
* Better word splitting than the PEAR package provides.
*
* @since 2.6.0
* @uses Text_Diff_Renderer_inline Extends
*/
#[AllowDynamicProperties]
class WP_Text_Diff_Renderer_inline extends Text_Diff_Renderer_inline {
/**
* @ignore
* @since 2.6.0
*
* @param string $string
* @param string $newlineEscape
* @return string
*/
public function _splitOnWords( $string, $newlineEscape = "\n" ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound,WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
$string = str_replace( "\0", '', $string );
$words = preg_split( '/([^\w])/u', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
$words = str_replace( "\n", $newlineEscape, $words ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
return $words;
}
}
<?php
/**
* API for fetching the HTML to embed remote content based on a provided URL
*
* Used internally by the WP_Embed class, but is designed to be generic.
*
* @link https://developer.wordpress.org/advanced-administration/wordpress/oembed/
* @link http://oembed.com/
*
* @package WordPress
* @subpackage oEmbed
*/
/**
* Core class used to implement oEmbed functionality.
*
* @since 2.9.0
*/
#[AllowDynamicProperties]
class WP_oEmbed {
/**
* A list of oEmbed providers.
*
* @since 2.9.0
* @var array
*/
public $providers = array();
/**
* A list of an early oEmbed providers.
*
* @since 4.0.0
* @var array
*/
public static $early_providers = array();
/**
* A list of private/protected methods, used for backward compatibility.
*
* @since 4.2.0
* @var array
*/
private $compat_methods = array( '_fetch_with_format', '_parse_json', '_parse_xml', '_parse_xml_body' );
/**
* Constructor.
*
* @since 2.9.0
*/
public function __construct() {
$host = urlencode( home_url() );
$providers = array(
'#https?://((m|www)\.)?youtube\.com/watch.*#i' => array( 'https://www.youtube.com/oembed', true ),
'#https?://((m|www)\.)?youtube\.com/playlist.*#i' => array( 'https://www.youtube.com/oembed', true ),
'#https?://((m|www)\.)?youtube\.com/shorts/*#i' => array( 'https://www.youtube.com/oembed', true ),
'#https?://((m|www)\.)?youtube\.com/live/*#i' => array( 'https://www.youtube.com/oembed', true ),
'#https?://youtu\.be/.*#i' => array( 'https://www.youtube.com/oembed', true ),
'#https?://(.+\.)?vimeo\.com/.*#i' => array( 'https://vimeo.com/api/oembed.{format}', true ),
'#https?://(www\.)?dailymotion\.com/.*#i' => array( 'https://www.dailymotion.com/services/oembed', true ),
'#https?://dai\.ly/.*#i' => array( 'https://www.dailymotion.com/services/oembed', true ),
'#https?://(www\.)?flickr\.com/.*#i' => array( 'https://www.flickr.com/services/oembed/', true ),
'#https?://flic\.kr/.*#i' => array( 'https://www.flickr.com/services/oembed/', true ),
'#https?://(.+\.)?smugmug\.com/.*#i' => array( 'https://api.smugmug.com/services/oembed/', true ),
'#https?://(www\.)?scribd\.com/(doc|document)/.*#i' => array( 'https://www.scribd.com/services/oembed', true ),
'#https?://wordpress\.tv/.*#i' => array( 'https://wordpress.tv/oembed/', true ),
'#https?://(.+\.)?crowdsignal\.net/.*#i' => array( 'https://api.crowdsignal.com/oembed', true ),
'#https?://(.+\.)?polldaddy\.com/.*#i' => array( 'https://api.crowdsignal.com/oembed', true ),
'#https?://poll\.fm/.*#i' => array( 'https://api.crowdsignal.com/oembed', true ),
'#https?://(.+\.)?survey\.fm/.*#i' => array( 'https://api.crowdsignal.com/oembed', true ),
'#https?://(www\.)?twitter\.com/\w{1,15}/status(es)?/.*#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?twitter\.com/\w{1,15}$#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?twitter\.com/\w{1,15}/likes$#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?twitter\.com/\w{1,15}/lists/.*#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?twitter\.com/\w{1,15}/timelines/.*#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?twitter\.com/i/moments/.*#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?soundcloud\.com/.*#i' => array( 'https://soundcloud.com/oembed', true ),
'#https?://(open|play)\.spotify\.com/.*#i' => array( 'https://embed.spotify.com/oembed/', true ),
'#https?://(.+\.)?imgur\.com/.*#i' => array( 'https://api.imgur.com/oembed', true ),
'#https?://(www\.)?issuu\.com/.+/docs/.+#i' => array( 'https://issuu.com/oembed_wp', true ),
'#https?://(www\.)?mixcloud\.com/.*#i' => array( 'https://app.mixcloud.com/oembed/', true ),
'#https?://(www\.|embed\.)?ted\.com/talks/.*#i' => array( 'https://www.ted.com/services/v1/oembed.{format}', true ),
'#https?://(www\.)?(animoto|video214)\.com/play/.*#i' => array( 'https://animoto.com/oembeds/create', true ),
'#https?://(.+)\.tumblr\.com/.*#i' => array( 'https://www.tumblr.com/oembed/1.0', true ),
'#https?://(www\.)?kickstarter\.com/projects/.*#i' => array( 'https://www.kickstarter.com/services/oembed', true ),
'#https?://kck\.st/.*#i' => array( 'https://www.kickstarter.com/services/oembed', true ),
'#https?://cloudup\.com/.*#i' => array( 'https://cloudup.com/oembed', true ),
'#https?://(www\.)?reverbnation\.com/.*#i' => array( 'https://www.reverbnation.com/oembed', true ),
'#https?://videopress\.com/v/.*#' => array( 'https://public-api.wordpress.com/oembed/?for=' . $host, true ),
'#https?://(www\.)?reddit\.com/r/[^/]+/comments/.*#i' => array( 'https://www.reddit.com/oembed', true ),
'#https?://(www\.)?speakerdeck\.com/.*#i' => array( 'https://speakerdeck.com/oembed.{format}', true ),
'#https?://(www\.)?screencast\.com/.*#i' => array( 'https://api.screencast.com/external/oembed', true ),
'#https?://([a-z0-9-]+\.)?amazon\.(com|com\.mx|com\.br|ca)/.*#i' => array( 'https://read.amazon.com/kp/api/oembed', true ),
'#https?://([a-z0-9-]+\.)?amazon\.(co\.uk|de|fr|it|es|in|nl|ru)/.*#i' => array( 'https://read.amazon.co.uk/kp/api/oembed', true ),
'#https?://([a-z0-9-]+\.)?amazon\.(co\.jp|com\.au)/.*#i' => array( 'https://read.amazon.com.au/kp/api/oembed', true ),
'#https?://([a-z0-9-]+\.)?amazon\.cn/.*#i' => array( 'https://read.amazon.cn/kp/api/oembed', true ),
'#https?://(www\.)?a\.co/.*#i' => array( 'https://read.amazon.com/kp/api/oembed', true ),
'#https?://(www\.)?amzn\.to/.*#i' => array( 'https://read.amazon.com/kp/api/oembed', true ),
'#https?://(www\.)?amzn\.eu/.*#i' => array( 'https://read.amazon.co.uk/kp/api/oembed', true ),
'#https?://(www\.)?amzn\.in/.*#i' => array( 'https://read.amazon.in/kp/api/oembed', true ),
'#https?://(www\.)?amzn\.asia/.*#i' => array( 'https://read.amazon.com.au/kp/api/oembed', true ),
'#https?://(www\.)?z\.cn/.*#i' => array( 'https://read.amazon.cn/kp/api/oembed', true ),
'#https?://www\.someecards\.com/.+-cards/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ),
'#https?://www\.someecards\.com/usercards/viewcard/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ),
'#https?://some\.ly\/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ),
'#https?://(www\.)?tiktok\.com/.*/video/.*#i' => array( 'https://www.tiktok.com/oembed', true ),
'#https?://(www\.)?tiktok\.com/@.*#i' => array( 'https://www.tiktok.com/oembed', true ),
'#https?://([a-z]{2}|www)\.pinterest\.com(\.(au|mx))?/.*#i' => array( 'https://www.pinterest.com/oembed.json', true ),
'#https?://(www\.)?wolframcloud\.com/obj/.+#i' => array( 'https://www.wolframcloud.com/oembed', true ),
'#https?://pca\.st/.+#i' => array( 'https://pca.st/oembed.json', true ),
'#https?://((play|www)\.)?anghami\.com/.*#i' => array( 'https://api.anghami.com/rest/v1/oembed.view', true ),
'#https?://bsky.app/profile/.*/post/.*#i' => array( 'https://embed.bsky.app/oembed', true ),
'#https?://(www\.)?canva\.com/design/.*/view.*#i' => array( 'https://canva.com/_oembed', true ),
);
if ( ! empty( self::$early_providers['add'] ) ) {
foreach ( self::$early_providers['add'] as $format => $data ) {
$providers[ $format ] = $data;
}
}
if ( ! empty( self::$early_providers['remove'] ) ) {
foreach ( self::$early_providers['remove'] as $format ) {
unset( $providers[ $format ] );
}
}
self::$early_providers = array();
/**
* Filters the list of sanctioned oEmbed providers.
*
* Since WordPress 4.4, oEmbed discovery is enabled for all users and allows embedding of sanitized
* iframes. The providers in this list are sanctioned, meaning they are trusted and allowed to
* embed any content, such as iframes, videos, JavaScript, and arbitrary HTML.
*
* Supported providers:
*
* | Provider | Flavor | Since |
* | ------------ | ----------------------------------------- | ------- |
* | Dailymotion | dailymotion.com | 2.9.0 |
* | Flickr | flickr.com | 2.9.0 |
* | Scribd | scribd.com | 2.9.0 |
* | Vimeo | vimeo.com | 2.9.0 |
* | WordPress.tv | wordpress.tv | 2.9.0 |
* | YouTube | youtube.com/watch | 2.9.0 |
* | Crowdsignal | polldaddy.com | 3.0.0 |
* | SmugMug | smugmug.com | 3.0.0 |
* | YouTube | youtu.be | 3.0.0 |
* | Twitter | twitter.com | 3.4.0 |
* | SoundCloud | soundcloud.com | 3.5.0 |
* | Dailymotion | dai.ly | 3.6.0 |
* | Flickr | flic.kr | 3.6.0 |
* | Spotify | spotify.com | 3.6.0 |
* | Imgur | imgur.com | 3.9.0 |
* | Animoto | animoto.com | 4.0.0 |
* | Animoto | video214.com | 4.0.0 |
* | Issuu | issuu.com | 4.0.0 |
* | Mixcloud | mixcloud.com | 4.0.0 |
* | Crowdsignal | poll.fm | 4.0.0 |
* | TED | ted.com | 4.0.0 |
* | YouTube | youtube.com/playlist | 4.0.0 |
* | Tumblr | tumblr.com | 4.2.0 |
* | Kickstarter | kickstarter.com | 4.2.0 |
* | Kickstarter | kck.st | 4.2.0 |
* | Cloudup | cloudup.com | 4.3.0 |
* | ReverbNation | reverbnation.com | 4.4.0 |
* | VideoPress | videopress.com | 4.4.0 |
* | Reddit | reddit.com | 4.4.0 |
* | Speaker Deck | speakerdeck.com | 4.4.0 |
* | Twitter | twitter.com/timelines | 4.5.0 |
* | Twitter | twitter.com/moments | 4.5.0 |
* | Twitter | twitter.com/user | 4.7.0 |
* | Twitter | twitter.com/likes | 4.7.0 |
* | Twitter | twitter.com/lists | 4.7.0 |
* | Screencast | screencast.com | 4.8.0 |
* | Amazon | amazon.com (com.mx, com.br, ca) | 4.9.0 |
* | Amazon | amazon.de (fr, it, es, in, nl, ru, co.uk) | 4.9.0 |
* | Amazon | amazon.co.jp (com.au) | 4.9.0 |
* | Amazon | amazon.cn | 4.9.0 |
* | Amazon | a.co | 4.9.0 |
* | Amazon | amzn.to (eu, in, asia) | 4.9.0 |
* | Amazon | z.cn | 4.9.0 |
* | Someecards | someecards.com | 4.9.0 |
* | Someecards | some.ly | 4.9.0 |
* | Crowdsignal | survey.fm | 5.1.0 |
* | TikTok | tiktok.com | 5.4.0 |
* | Pinterest | pinterest.com | 5.9.0 |
* | WolframCloud | wolframcloud.com | 5.9.0 |
* | Pocket Casts | pocketcasts.com | 6.1.0 |
* | Crowdsignal | crowdsignal.net | 6.2.0 |
* | Anghami | anghami.com | 6.3.0 |
* | Bluesky | bsky.app | 6.6.0 |
* | Canva | canva.com | 6.8.0 |
*
* No longer supported providers:
*
* | Provider | Flavor | Since | Removed |
* | ------------ | -------------------- | --------- | --------- |
* | Qik | qik.com | 2.9.0 | 3.9.0 |
* | Viddler | viddler.com | 2.9.0 | 4.0.0 |
* | Revision3 | revision3.com | 2.9.0 | 4.2.0 |
* | Blip | blip.tv | 2.9.0 | 4.4.0 |
* | Rdio | rdio.com | 3.6.0 | 4.4.1 |
* | Rdio | rd.io | 3.6.0 | 4.4.1 |
* | Vine | vine.co | 4.1.0 | 4.9.0 |
* | Photobucket | photobucket.com | 2.9.0 | 5.1.0 |
* | Funny or Die | funnyordie.com | 3.0.0 | 5.1.0 |
* | CollegeHumor | collegehumor.com | 4.0.0 | 5.3.1 |
* | Hulu | hulu.com | 2.9.0 | 5.5.0 |
* | Instagram | instagram.com | 3.5.0 | 5.5.2 |
* | Instagram | instagr.am | 3.5.0 | 5.5.2 |
* | Instagram TV | instagram.com | 5.1.0 | 5.5.2 |
* | Instagram TV | instagr.am | 5.1.0 | 5.5.2 |
* | Facebook | facebook.com | 4.7.0 | 5.5.2 |
* | Meetup.com | meetup.com | 3.9.0 | 6.0.1 |
* | Meetup.com | meetu.ps | 3.9.0 | 6.0.1 |
* | SlideShare | slideshare.net | 3.5.0 | 6.6.0 |
*
* @see wp_oembed_add_provider()
*
* @since 2.9.0
*
* @param array[] $providers An array of arrays containing data about popular oEmbed providers.
*/
$this->providers = apply_filters( 'oembed_providers', $providers );
// Fix any embeds that contain new lines in the middle of the HTML which breaks wpautop().
add_filter( 'oembed_dataparse', array( $this, '_strip_newlines' ), 10, 3 );
}
/**
* Exposes private/protected methods for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Method to call.
* @param array $arguments Arguments to pass when calling.
* @return mixed|false Return value of the callback, false otherwise.
*/
public function __call( $name, $arguments ) {
if ( in_array( $name, $this->compat_methods, true ) ) {
return $this->$name( ...$arguments );
}
return false;
}
/**
* Takes a URL and returns the corresponding oEmbed provider's URL, if there is one.
*
* @since 4.0.0
*
* @see WP_oEmbed::discover()
*
* @param string $url The URL to the content.
* @param string|array $args {
* Optional. Additional provider arguments. Default empty.
*
* @type bool $discover Optional. Determines whether to attempt to discover link tags
* at the given URL for an oEmbed provider when the provider URL
* is not found in the built-in providers list. Default true.
* }
* @return string|false The oEmbed provider URL on success, false on failure.
*/
public function get_provider( $url, $args = '' ) {
$args = wp_parse_args( $args );
$provider = false;
if ( ! isset( $args['discover'] ) ) {
$args['discover'] = true;
}
foreach ( $this->providers as $matchmask => $data ) {
list( $providerurl, $regex ) = $data;
// Turn the asterisk-type provider URLs into regex.
if ( ! $regex ) {
$matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i';
$matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask );
}
if ( preg_match( $matchmask, $url ) ) {
$provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML.
break;
}
}
if ( ! $provider && $args['discover'] ) {
$provider = $this->discover( $url );
}
return $provider;
}
/**
* Adds an oEmbed provider.
*
* The provider is added just-in-time when wp_oembed_add_provider() is called before
* the {@see 'plugins_loaded'} hook.
*
* The just-in-time addition is for the benefit of the {@see 'oembed_providers'} filter.
*
* @since 4.0.0
*
* @see wp_oembed_add_provider()
*
* @param string $format Format of URL that this provider can handle. You can use
* asterisks as wildcards.
* @param string $provider The URL to the oEmbed provider..
* @param bool $regex Optional. Whether the $format parameter is in a regex format.
* Default false.
*/
public static function _add_provider_early( $format, $provider, $regex = false ) {
if ( empty( self::$early_providers['add'] ) ) {
self::$early_providers['add'] = array();
}
self::$early_providers['add'][ $format ] = array( $provider, $regex );
}
/**
* Removes an oEmbed provider.
*
* The provider is removed just-in-time when wp_oembed_remove_provider() is called before
* the {@see 'plugins_loaded'} hook.
*
* The just-in-time removal is for the benefit of the {@see 'oembed_providers'} filter.
*
* @since 4.0.0
*
* @see wp_oembed_remove_provider()
*
* @param string $format The format of URL that this provider can handle. You can use
* asterisks as wildcards.
*/
public static function _remove_provider_early( $format ) {
if ( empty( self::$early_providers['remove'] ) ) {
self::$early_providers['remove'] = array();
}
self::$early_providers['remove'][] = $format;
}
/**
* Takes a URL and attempts to return the oEmbed data.
*
* @see WP_oEmbed::fetch()
*
* @since 4.8.0
*
* @param string $url The URL to the content that should be attempted to be embedded.
* @param string|array $args Optional. Additional arguments for retrieving embed HTML.
* See wp_oembed_get() for accepted arguments. Default empty.
* @return object|false The result in the form of an object on success, false on failure.
*/
public function get_data( $url, $args = '' ) {
$args = wp_parse_args( $args );
$provider = $this->get_provider( $url, $args );
if ( ! $provider ) {
return false;
}
$data = $this->fetch( $provider, $url, $args );
if ( false === $data ) {
return false;
}
return $data;
}
/**
* The do-it-all function that takes a URL and attempts to return the HTML.
*
* @see WP_oEmbed::fetch()
* @see WP_oEmbed::data2html()
*
* @since 2.9.0
*
* @param string $url The URL to the content that should be attempted to be embedded.
* @param string|array $args Optional. Additional arguments for retrieving embed HTML.
* See wp_oembed_get() for accepted arguments. Default empty.
* @return string|false The UNSANITIZED (and potentially unsafe) HTML that should be used to embed
* on success, false on failure.
*/
public function get_html( $url, $args = '' ) {
/**
* Filters the oEmbed result before any HTTP requests are made.
*
* This allows one to short-circuit the default logic, perhaps by
* replacing it with a routine that is more optimal for your setup.
*
* Returning a non-null value from the filter will effectively short-circuit retrieval
* and return the passed value instead.
*
* @since 4.5.3
*
* @param null|string $result The UNSANITIZED (and potentially unsafe) HTML that should be used to embed.
* Default null to continue retrieving the result.
* @param string $url The URL to the content that should be attempted to be embedded.
* @param string|array $args Optional. Additional arguments for retrieving embed HTML.
* See wp_oembed_get() for accepted arguments. Default empty.
*/
$pre = apply_filters( 'pre_oembed_result', null, $url, $args );
if ( null !== $pre ) {
return $pre;
}
$data = $this->get_data( $url, $args );
if ( false === $data ) {
return false;
}
/**
* Filters the HTML returned by the oEmbed provider.
*
* @since 2.9.0
*
* @param string|false $data The returned oEmbed HTML (false if unsafe).
* @param string $url URL of the content to be embedded.
* @param string|array $args Optional. Additional arguments for retrieving embed HTML.
* See wp_oembed_get() for accepted arguments. Default empty.
*/
return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args );
}
/**
* Attempts to discover link tags at the given URL for an oEmbed provider.
*
* @since 2.9.0
*
* @param string $url The URL that should be inspected for discovery `<link>` tags.
* @return string|false The oEmbed provider URL on success, false on failure.
*/
public function discover( $url ) {
$providers = array();
$args = array(
'limit_response_size' => 153600, // 150 KB
);
/**
* Filters oEmbed remote get arguments.
*
* @since 4.0.0
*
* @see WP_Http::request()
*
* @param array $args oEmbed remote get arguments.
* @param string $url URL to be inspected.
*/
$args = apply_filters( 'oembed_remote_get_args', $args, $url );
// Fetch URL content.
$request = wp_safe_remote_get( $url, $args );
$html = wp_remote_retrieve_body( $request );
if ( $html ) {
/**
* Filters the link types that contain oEmbed provider URLs.
*
* @since 2.9.0
*
* @param string[] $format Array of oEmbed link types. Accepts 'application/json+oembed',
* 'text/xml+oembed', and 'application/xml+oembed' (incorrect,
* used by at least Vimeo).
*/
$linktypes = apply_filters(
'oembed_linktypes',
array(
'application/json+oembed' => 'json',
'text/xml+oembed' => 'xml',
'application/xml+oembed' => 'xml',
)
);
// Strip <body>.
$html_head_end = stripos( $html, '</head>' );
if ( $html_head_end ) {
$html = substr( $html, 0, $html_head_end );
}
// Do a quick check.
$tagfound = false;
foreach ( $linktypes as $linktype => $format ) {
if ( stripos( $html, $linktype ) ) {
$tagfound = true;
break;
}
}
if ( $tagfound && preg_match_all( '#<link([^<>]+)/?>#iU', $html, $links ) ) {
foreach ( $links[1] as $link ) {
$atts = shortcode_parse_atts( $link );
if ( ! empty( $atts['type'] ) && ! empty( $linktypes[ $atts['type'] ] ) && ! empty( $atts['href'] ) ) {
$providers[ $linktypes[ $atts['type'] ] ] = htmlspecialchars_decode( $atts['href'] );
// Stop here if it's JSON (that's all we need).
if ( 'json' === $linktypes[ $atts['type'] ] ) {
break;
}
}
}
}
}
// JSON is preferred to XML.
if ( ! empty( $providers['json'] ) ) {
return $providers['json'];
} elseif ( ! empty( $providers['xml'] ) ) {
return $providers['xml'];
} else {
return false;
}
}
/**
* Connects to an oEmbed provider and returns the result.
*
* @since 2.9.0
*
* @param string $provider The URL to the oEmbed provider.
* @param string $url The URL to the content that is desired to be embedded.
* @param string|array $args Optional. Additional arguments for retrieving embed HTML.
* See wp_oembed_get() for accepted arguments. Default empty.
* @return object|false The result in the form of an object on success, false on failure.
*/
public function fetch( $provider, $url, $args = '' ) {
$args = wp_parse_args( $args, wp_embed_defaults( $url ) );
$provider = add_query_arg( 'maxwidth', (int) $args['width'], $provider );
$provider = add_query_arg( 'maxheight', (int) $args['height'], $provider );
$provider = add_query_arg( 'url', urlencode( $url ), $provider );
$provider = add_query_arg( 'dnt', 1, $provider );
/**
* Filters the oEmbed URL to be fetched.
*
* @since 2.9.0
* @since 4.9.0 The `dnt` (Do Not Track) query parameter was added to all oEmbed provider URLs.
*
* @param string $provider URL of the oEmbed provider.
* @param string $url URL of the content to be embedded.
* @param array $args Optional. Additional arguments for retrieving embed HTML.
* See wp_oembed_get() for accepted arguments. Default empty.
*/
$provider = apply_filters( 'oembed_fetch_url', $provider, $url, $args );
foreach ( array( 'json', 'xml' ) as $format ) {
$result = $this->_fetch_with_format( $provider, $format );
if ( is_wp_error( $result ) && 'not-implemented' === $result->get_error_code() ) {
continue;
}
return ( $result && ! is_wp_error( $result ) ) ? $result : false;
}
return false;
}
/**
* Fetches result from an oEmbed provider for a specific format and complete provider URL
*
* @since 3.0.0
*
* @param string $provider_url_with_args URL to the provider with full arguments list (url, maxheight, etc.)
* @param string $format Format to use.
* @return object|false|WP_Error The result in the form of an object on success, false on failure.
*/
private function _fetch_with_format( $provider_url_with_args, $format ) {
$provider_url_with_args = add_query_arg( 'format', $format, $provider_url_with_args );
/** This filter is documented in wp-includes/class-wp-oembed.php */
$args = apply_filters( 'oembed_remote_get_args', array(), $provider_url_with_args );
$response = wp_safe_remote_get( $provider_url_with_args, $args );
if ( 501 === wp_remote_retrieve_response_code( $response ) ) {
return new WP_Error( 'not-implemented' );
}
$body = wp_remote_retrieve_body( $response );
if ( ! $body ) {
return false;
}
$parse_method = "_parse_$format";
return $this->$parse_method( $body );
}
/**
* Parses a json response body.
*
* @since 3.0.0
*
* @param string $response_body
* @return object|false
*/
private function _parse_json( $response_body ) {
$data = json_decode( trim( $response_body ) );
return ( $data && is_object( $data ) ) ? $data : false;
}
/**
* Parses an XML response body.
*
* @since 3.0.0
*
* @param string $response_body
* @return object|false
*/
private function _parse_xml( $response_body ) {
if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
return false;
}
if ( PHP_VERSION_ID < 80000 ) {
/*
* This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading
* is disabled by default, so this function is no longer needed to protect against XXE attacks.
*/
$loader = libxml_disable_entity_loader( true );
}
$errors = libxml_use_internal_errors( true );
$return = $this->_parse_xml_body( $response_body );
libxml_use_internal_errors( $errors );
if ( PHP_VERSION_ID < 80000 && isset( $loader ) ) {
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.libxml_disable_entity_loaderDeprecated
libxml_disable_entity_loader( $loader );
}
return $return;
}
/**
* Serves as a helper function for parsing an XML response body.
*
* @since 3.6.0
*
* @param string $response_body
* @return stdClass|false
*/
private function _parse_xml_body( $response_body ) {
if ( ! function_exists( 'simplexml_import_dom' ) || ! class_exists( 'DOMDocument', false ) ) {
return false;
}
$dom = new DOMDocument();
$success = $dom->loadXML( $response_body );
if ( ! $success ) {
return false;
}
if ( isset( $dom->doctype ) ) {
return false;
}
foreach ( $dom->childNodes as $child ) {
if ( XML_DOCUMENT_TYPE_NODE === $child->nodeType ) {
return false;
}
}
$xml = simplexml_import_dom( $dom );
if ( ! $xml ) {
return false;
}
$return = new stdClass();
foreach ( $xml as $key => $value ) {
$return->$key = (string) $value;
}
return $return;
}
/**
* Converts a data object from WP_oEmbed::fetch() and returns the HTML.
*
* @since 2.9.0
*
* @param object $data A data object result from an oEmbed provider.
* @param string $url The URL to the content that is desired to be embedded.
* @return string|false The HTML needed to embed on success, false on failure.
*/
public function data2html( $data, $url ) {
if ( ! is_object( $data ) || empty( $data->type ) ) {
return false;
}
$return = false;
switch ( $data->type ) {
case 'photo':
if ( empty( $data->url ) || empty( $data->width ) || empty( $data->height ) ) {
break;
}
if ( ! is_string( $data->url ) || ! is_numeric( $data->width ) || ! is_numeric( $data->height ) ) {
break;
}
$title = ! empty( $data->title ) && is_string( $data->title ) ? $data->title : '';
$return = '<a href="' . esc_url( $url ) . '"><img src="' . esc_url( $data->url ) . '" alt="' . esc_attr( $title ) . '" width="' . esc_attr( $data->width ) . '" height="' . esc_attr( $data->height ) . '" /></a>';
break;
case 'video':
case 'rich':
if ( ! empty( $data->html ) && is_string( $data->html ) ) {
$return = $data->html;
}
break;
case 'link':
if ( ! empty( $data->title ) && is_string( $data->title ) ) {
$return = '<a href="' . esc_url( $url ) . '">' . esc_html( $data->title ) . '</a>';
}
break;
default:
$return = false;
}
/**
* Filters the returned oEmbed HTML.
*
* Use this filter to add support for custom data types, or to filter the result.
*
* @since 2.9.0
*
* @param string $return The returned oEmbed HTML.
* @param object $data A data object result from an oEmbed provider.
* @param string $url The URL of the content to be embedded.
*/
return apply_filters( 'oembed_dataparse', $return, $data, $url );
}
/**
* Strips any new lines from the HTML.
*
* @since 2.9.0 as strip_scribd_newlines()
* @since 3.0.0
*
* @param string $html Existing HTML.
* @param object $data Data object from WP_oEmbed::data2html()
* @param string $url The original URL passed to oEmbed.
* @return string Possibly modified $html
*/
public function _strip_newlines( $html, $data, $url ) {
if ( ! str_contains( $html, "\n" ) ) {
return $html;
}
$count = 1;
$found = array();
$token = '__PRE__';
$search = array( "\t", "\n", "\r", ' ' );
$replace = array( '__TAB__', '__NL__', '__CR__', '__SPACE__' );
$tokenized = str_replace( $search, $replace, $html );
preg_match_all( '#(<pre[^>]*>.+?</pre>)#i', $tokenized, $matches, PREG_SET_ORDER );
foreach ( $matches as $i => $match ) {
$tag_html = str_replace( $replace, $search, $match[0] );
$tag_token = $token . $i;
$found[ $tag_token ] = $tag_html;
$html = str_replace( $tag_html, $tag_token, $html, $count );
}
$replaced = str_replace( $replace, $search, $html );
$stripped = str_replace( array( "\r\n", "\n" ), '', $replaced );
$pre = array_values( $found );
$tokens = array_keys( $found );
return str_replace( $tokens, $pre, $stripped );
}
}
<?php
/**
* WordPress API for media display.
*
* @package WordPress
* @subpackage Media
*/
// Don't load directly.
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
/**
* Retrieves additional image sizes.
*
* @since 4.7.0
*
* @global array $_wp_additional_image_sizes
*
* @return array Additional images size data.
*/
function wp_get_additional_image_sizes() {
global $_wp_additional_image_sizes;
if ( ! $_wp_additional_image_sizes ) {
$_wp_additional_image_sizes = array();
}
return $_wp_additional_image_sizes;
}
/**
* Scales down the default size of an image.
*
* This is so that the image is a better fit for the editor and theme.
*
* The `$size` parameter accepts either an array or a string. The supported string
* values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at
* 128 width and 96 height in pixels. Also supported for the string value is
* 'medium', 'medium_large' and 'full'. The 'full' isn't actually supported, but any value other
* than the supported will result in the content_width size or 500 if that is
* not set.
*
* Finally, there is a filter named {@see 'editor_max_image_size'}, that will be
* called on the calculated array for width and height, respectively.
*
* @since 2.5.0
*
* @global int $content_width
*
* @param int $width Width of the image in pixels.
* @param int $height Height of the image in pixels.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'medium'.
* @param string $context Optional. Could be 'display' (like in a theme) or 'edit'
* (like inserting into an editor). Default null.
* @return int[] {
* An array of width and height values.
*
* @type int $0 The maximum width in pixels.
* @type int $1 The maximum height in pixels.
* }
*/
function image_constrain_size_for_editor( $width, $height, $size = 'medium', $context = null ) {
global $content_width;
$_wp_additional_image_sizes = wp_get_additional_image_sizes();
if ( ! $context ) {
$context = is_admin() ? 'edit' : 'display';
}
if ( is_array( $size ) ) {
$max_width = $size[0];
$max_height = $size[1];
} elseif ( 'thumb' === $size || 'thumbnail' === $size ) {
$max_width = (int) get_option( 'thumbnail_size_w' );
$max_height = (int) get_option( 'thumbnail_size_h' );
// Last chance thumbnail size defaults.
if ( ! $max_width && ! $max_height ) {
$max_width = 128;
$max_height = 96;
}
} elseif ( 'medium' === $size ) {
$max_width = (int) get_option( 'medium_size_w' );
$max_height = (int) get_option( 'medium_size_h' );
} elseif ( 'medium_large' === $size ) {
$max_width = (int) get_option( 'medium_large_size_w' );
$max_height = (int) get_option( 'medium_large_size_h' );
if ( (int) $content_width > 0 ) {
$max_width = min( (int) $content_width, $max_width );
}
} elseif ( 'large' === $size ) {
/*
* We're inserting a large size image into the editor. If it's a really
* big image we'll scale it down to fit reasonably within the editor
* itself, and within the theme's content width if it's known. The user
* can resize it in the editor if they wish.
*/
$max_width = (int) get_option( 'large_size_w' );
$max_height = (int) get_option( 'large_size_h' );
if ( (int) $content_width > 0 ) {
$max_width = min( (int) $content_width, $max_width );
}
} elseif ( ! empty( $_wp_additional_image_sizes ) && in_array( $size, array_keys( $_wp_additional_image_sizes ), true ) ) {
$max_width = (int) $_wp_additional_image_sizes[ $size ]['width'];
$max_height = (int) $_wp_additional_image_sizes[ $size ]['height'];
// Only in admin. Assume that theme authors know what they're doing.
if ( (int) $content_width > 0 && 'edit' === $context ) {
$max_width = min( (int) $content_width, $max_width );
}
} else { // $size === 'full' has no constraint.
$max_width = $width;
$max_height = $height;
}
/**
* Filters the maximum image size dimensions for the editor.
*
* @since 2.5.0
*
* @param int[] $max_image_size {
* An array of width and height values.
*
* @type int $0 The maximum width in pixels.
* @type int $1 The maximum height in pixels.
* }
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param string $context The context the image is being resized for.
* Possible values are 'display' (like in a theme)
* or 'edit' (like inserting into an editor).
*/
list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size, $context );
return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
}
/**
* Retrieves width and height attributes using given width and height values.
*
* Both attributes are required in the sense that both parameters must have a
* value, but are optional in that if you set them to false or null, then they
* will not be added to the returned string.
*
* You can set the value using a string, but it will only take numeric values.
* If you wish to put 'px' after the numbers, then it will be stripped out of
* the return.
*
* @since 2.5.0
*
* @param int|string $width Image width in pixels.
* @param int|string $height Image height in pixels.
* @return string HTML attributes for width and, or height.
*/
function image_hwstring( $width, $height ) {
$out = '';
if ( $width ) {
$out .= 'width="' . (int) $width . '" ';
}
if ( $height ) {
$out .= 'height="' . (int) $height . '" ';
}
return $out;
}
/**
* Scales an image to fit a particular size (such as 'thumb' or 'medium').
*
* The URL might be the original image, or it might be a resized version. This
* function won't create a new resized copy, it will just return an already
* resized one if it exists.
*
* A plugin may use the {@see 'image_downsize'} filter to hook into and offer image
* resizing services for images. The hook must return an array with the same
* elements that are normally returned from the function.
*
* @since 2.5.0
*
* @param int $id Attachment ID for image.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'medium'.
* @return array|false {
* Array of image data, or boolean false if no image is available.
*
* @type string $0 Image source URL.
* @type int $1 Image width in pixels.
* @type int $2 Image height in pixels.
* @type bool $3 Whether the image is a resized image.
* }
*/
function image_downsize( $id, $size = 'medium' ) {
$is_image = wp_attachment_is_image( $id );
/**
* Filters whether to preempt the output of image_downsize().
*
* Returning a truthy value from the filter will effectively short-circuit
* down-sizing the image, returning that value instead.
*
* @since 2.5.0
*
* @param bool|array $downsize Whether to short-circuit the image downsize.
* @param int $id Attachment ID for image.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
*/
$out = apply_filters( 'image_downsize', false, $id, $size );
if ( $out ) {
return $out;
}
$img_url = wp_get_attachment_url( $id );
$meta = wp_get_attachment_metadata( $id );
$width = 0;
$height = 0;
$is_intermediate = false;
$img_url_basename = wp_basename( $img_url );
/*
* If the file isn't an image, attempt to replace its URL with a rendered image from its meta.
* Otherwise, a non-image type could be returned.
*/
if ( ! $is_image ) {
if ( ! empty( $meta['sizes']['full'] ) ) {
$img_url = str_replace( $img_url_basename, $meta['sizes']['full']['file'], $img_url );
$img_url_basename = $meta['sizes']['full']['file'];
$width = $meta['sizes']['full']['width'];
$height = $meta['sizes']['full']['height'];
} else {
return false;
}
}
// Try for a new style intermediate size.
$intermediate = image_get_intermediate_size( $id, $size );
if ( $intermediate ) {
$img_url = str_replace( $img_url_basename, $intermediate['file'], $img_url );
$width = $intermediate['width'];
$height = $intermediate['height'];
$is_intermediate = true;
} elseif ( 'thumbnail' === $size && ! empty( $meta['thumb'] ) && is_string( $meta['thumb'] ) ) {
// Fall back to the old thumbnail.
$imagefile = get_attached_file( $id );
$thumbfile = str_replace( wp_basename( $imagefile ), wp_basename( $meta['thumb'] ), $imagefile );
if ( file_exists( $thumbfile ) ) {
$info = wp_getimagesize( $thumbfile );
if ( $info ) {
$img_url = str_replace( $img_url_basename, wp_basename( $thumbfile ), $img_url );
$width = $info[0];
$height = $info[1];
$is_intermediate = true;
}
}
}
if ( ! $width && ! $height && isset( $meta['width'], $meta['height'] ) ) {
// Any other type: use the real image.
$width = $meta['width'];
$height = $meta['height'];
}
if ( $img_url ) {
// We have the actual image size, but might need to further constrain it if content_width is narrower.
list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
return array( $img_url, $width, $height, $is_intermediate );
}
return false;
}
/**
* Registers a new image size.
*
* @since 2.9.0
*
* @global array $_wp_additional_image_sizes Associative array of additional image sizes.
*
* @param string $name Image size identifier.
* @param int $width Optional. Image width in pixels. Default 0.
* @param int $height Optional. Image height in pixels. Default 0.
* @param bool|array $crop {
* Optional. Image cropping behavior. If false, the image will be scaled (default).
* If true, image will be cropped to the specified dimensions using center positions.
* If an array, the image will be cropped using the array to specify the crop location:
*
* @type string $0 The x crop position. Accepts 'left', 'center', or 'right'.
* @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
* }
*/
function add_image_size( $name, $width = 0, $height = 0, $crop = false ) {
global $_wp_additional_image_sizes;
$_wp_additional_image_sizes[ $name ] = array(
'width' => absint( $width ),
'height' => absint( $height ),
'crop' => $crop,
);
}
/**
* Checks if an image size exists.
*
* @since 3.9.0
*
* @param string $name The image size to check.
* @return bool True if the image size exists, false if not.
*/
function has_image_size( $name ) {
$sizes = wp_get_additional_image_sizes();
return isset( $sizes[ $name ] );
}
/**
* Removes a new image size.
*
* @since 3.9.0
*
* @global array $_wp_additional_image_sizes
*
* @param string $name The image size to remove.
* @return bool True if the image size was successfully removed, false on failure.
*/
function remove_image_size( $name ) {
global $_wp_additional_image_sizes;
if ( isset( $_wp_additional_image_sizes[ $name ] ) ) {
unset( $_wp_additional_image_sizes[ $name ] );
return true;
}
return false;
}
/**
* Registers an image size for the post thumbnail.
*
* @since 2.9.0
*
* @see add_image_size() for details on cropping behavior.
*
* @param int $width Image width in pixels.
* @param int $height Image height in pixels.
* @param bool|array $crop {
* Optional. Image cropping behavior. If false, the image will be scaled (default).
* If true, image will be cropped to the specified dimensions using center positions.
* If an array, the image will be cropped using the array to specify the crop location:
*
* @type string $0 The x crop position. Accepts 'left', 'center', or 'right'.
* @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
* }
*/
function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) {
add_image_size( 'post-thumbnail', $width, $height, $crop );
}
/**
* Gets an img tag for an image attachment, scaling it down if requested.
*
* The {@see 'get_image_tag_class'} filter allows for changing the class name for the
* image without having to use regular expressions on the HTML content. The
* parameters are: what WordPress will use for the class, the Attachment ID,
* image align value, and the size the image should be.
*
* The second filter, {@see 'get_image_tag'}, has the HTML content, which can then be
* further manipulated by a plugin to change all attribute values and even HTML
* content.
*
* @since 2.5.0
*
* @param int $id Attachment ID.
* @param string $alt Image description for the alt attribute.
* @param string $title Image description for the title attribute.
* @param string $align Part of the class name for aligning the image.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'medium'.
* @return string HTML IMG element for given image attachment.
*/
function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) {
list( $img_src, $width, $height ) = image_downsize( $id, $size );
$hwstring = image_hwstring( $width, $height );
$title = $title ? 'title="' . esc_attr( $title ) . '" ' : '';
$size_class = is_array( $size ) ? implode( 'x', $size ) : $size;
$class = 'align' . esc_attr( $align ) . ' size-' . esc_attr( $size_class ) . ' wp-image-' . $id;
/**
* Filters the value of the attachment's image tag class attribute.
*
* @since 2.6.0
*
* @param string $class CSS class name or space-separated list of classes.
* @param int $id Attachment ID.
* @param string $align Part of the class name for aligning the image.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
*/
$class = apply_filters( 'get_image_tag_class', $class, $id, $align, $size );
$html = '<img src="' . esc_url( $img_src ) . '" alt="' . esc_attr( $alt ) . '" ' . $title . $hwstring . 'class="' . $class . '" />';
/**
* Filters the HTML content for the image tag.
*
* @since 2.6.0
*
* @param string $html HTML content for the image.
* @param int $id Attachment ID.
* @param string $alt Image description for the alt attribute.
* @param string $title Image description for the title attribute.
* @param string $align Part of the class name for aligning the image.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
*/
return apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
}
/**
* Calculates the new dimensions for a down-sampled image.
*
* If either width or height are empty, no constraint is applied on
* that dimension.
*
* @since 2.5.0
*
* @param int $current_width Current width of the image.
* @param int $current_height Current height of the image.
* @param int $max_width Optional. Max width in pixels to constrain to. Default 0.
* @param int $max_height Optional. Max height in pixels to constrain to. Default 0.
* @return int[] {
* An array of width and height values.
*
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* }
*/
function wp_constrain_dimensions( $current_width, $current_height, $max_width = 0, $max_height = 0 ) {
if ( ! $max_width && ! $max_height ) {
return array( $current_width, $current_height );
}
$width_ratio = 1.0;
$height_ratio = 1.0;
$did_width = false;
$did_height = false;
if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) {
$width_ratio = $max_width / $current_width;
$did_width = true;
}
if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) {
$height_ratio = $max_height / $current_height;
$did_height = true;
}
// Calculate the larger/smaller ratios.
$smaller_ratio = min( $width_ratio, $height_ratio );
$larger_ratio = max( $width_ratio, $height_ratio );
if ( (int) round( $current_width * $larger_ratio ) > $max_width || (int) round( $current_height * $larger_ratio ) > $max_height ) {
// The larger ratio is too big. It would result in an overflow.
$ratio = $smaller_ratio;
} else {
// The larger ratio fits, and is likely to be a more "snug" fit.
$ratio = $larger_ratio;
}
// Very small dimensions may result in 0, 1 should be the minimum.
$w = max( 1, (int) round( $current_width * $ratio ) );
$h = max( 1, (int) round( $current_height * $ratio ) );
/*
* Sometimes, due to rounding, we'll end up with a result like this:
* 465x700 in a 177x177 box is 117x176... a pixel short.
* We also have issues with recursive calls resulting in an ever-changing result.
* Constraining to the result of a constraint should yield the original result.
* Thus we look for dimensions that are one pixel shy of the max value and bump them up.
*/
// Note: $did_width means it is possible $smaller_ratio == $width_ratio.
if ( $did_width && $w === $max_width - 1 ) {
$w = $max_width; // Round it up.
}
// Note: $did_height means it is possible $smaller_ratio == $height_ratio.
if ( $did_height && $h === $max_height - 1 ) {
$h = $max_height; // Round it up.
}
/**
* Filters dimensions to constrain down-sampled images to.
*
* @since 4.1.0
*
* @param int[] $dimensions {
* An array of width and height values.
*
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* }
* @param int $current_width The current width of the image.
* @param int $current_height The current height of the image.
* @param int $max_width The maximum width permitted.
* @param int $max_height The maximum height permitted.
*/
return apply_filters( 'wp_constrain_dimensions', array( $w, $h ), $current_width, $current_height, $max_width, $max_height );
}
/**
* Retrieves calculated resize dimensions for use in WP_Image_Editor.
*
* Calculates dimensions and coordinates for a resized image that fits
* within a specified width and height.
*
* @since 2.5.0
*
* @param int $orig_w Original width in pixels.
* @param int $orig_h Original height in pixels.
* @param int $dest_w New width in pixels.
* @param int $dest_h New height in pixels.
* @param bool|array $crop {
* Optional. Image cropping behavior. If false, the image will be scaled (default).
* If true, image will be cropped to the specified dimensions using center positions.
* If an array, the image will be cropped using the array to specify the crop location:
*
* @type string $0 The x crop position. Accepts 'left', 'center', or 'right'.
* @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
* }
* @return array|false Returned array matches parameters for `imagecopyresampled()`. False on failure.
*/
function image_resize_dimensions( $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) {
if ( $orig_w <= 0 || $orig_h <= 0 ) {
return false;
}
// At least one of $dest_w or $dest_h must be specific.
if ( $dest_w <= 0 && $dest_h <= 0 ) {
return false;
}
/**
* Filters whether to preempt calculating the image resize dimensions.
*
* Returning a non-null value from the filter will effectively short-circuit
* image_resize_dimensions(), returning that value instead.
*
* @since 3.4.0
*
* @param null|mixed $null Whether to preempt output of the resize dimensions.
* @param int $orig_w Original width in pixels.
* @param int $orig_h Original height in pixels.
* @param int $dest_w New width in pixels.
* @param int $dest_h New height in pixels.
* @param bool|array $crop Whether to crop image to specified width and height or resize.
* An array can specify positioning of the crop area. Default false.
*/
$output = apply_filters( 'image_resize_dimensions', null, $orig_w, $orig_h, $dest_w, $dest_h, $crop );
if ( null !== $output ) {
return $output;
}
// Stop if the destination size is larger than the original image dimensions.
if ( empty( $dest_h ) ) {
if ( $orig_w < $dest_w ) {
return false;
}
} elseif ( empty( $dest_w ) ) {
if ( $orig_h < $dest_h ) {
return false;
}
} else {
if ( $orig_w < $dest_w && $orig_h < $dest_h ) {
return false;
}
}
if ( $crop ) {
/*
* Crop the largest possible portion of the original image that we can size to $dest_w x $dest_h.
* Note that the requested crop dimensions are used as a maximum bounding box for the original image.
* If the original image's width or height is less than the requested width or height
* only the greater one will be cropped.
* For example when the original image is 600x300, and the requested crop dimensions are 400x400,
* the resulting image will be 400x300.
*/
$aspect_ratio = $orig_w / $orig_h;
$new_w = min( $dest_w, $orig_w );
$new_h = min( $dest_h, $orig_h );
if ( ! $new_w ) {
$new_w = (int) round( $new_h * $aspect_ratio );
}
if ( ! $new_h ) {
$new_h = (int) round( $new_w / $aspect_ratio );
}
$size_ratio = max( $new_w / $orig_w, $new_h / $orig_h );
$crop_w = round( $new_w / $size_ratio );
$crop_h = round( $new_h / $size_ratio );
if ( ! is_array( $crop ) || count( $crop ) !== 2 ) {
$crop = array( 'center', 'center' );
}
list( $x, $y ) = $crop;
if ( 'left' === $x ) {
$s_x = 0;
} elseif ( 'right' === $x ) {
$s_x = $orig_w - $crop_w;
} else {
$s_x = floor( ( $orig_w - $crop_w ) / 2 );
}
if ( 'top' === $y ) {
$s_y = 0;
} elseif ( 'bottom' === $y ) {
$s_y = $orig_h - $crop_h;
} else {
$s_y = floor( ( $orig_h - $crop_h ) / 2 );
}
} else {
// Resize using $dest_w x $dest_h as a maximum bounding box.
$crop_w = $orig_w;
$crop_h = $orig_h;
$s_x = 0;
$s_y = 0;
list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
}
if ( wp_fuzzy_number_match( $new_w, $orig_w ) && wp_fuzzy_number_match( $new_h, $orig_h ) ) {
// The new size has virtually the same dimensions as the original image.
/**
* Filters whether to proceed with making an image sub-size with identical dimensions
* with the original/source image. Differences of 1px may be due to rounding and are ignored.
*
* @since 5.3.0
*
* @param bool $proceed The filtered value.
* @param int $orig_w Original image width.
* @param int $orig_h Original image height.
*/
$proceed = (bool) apply_filters( 'wp_image_resize_identical_dimensions', false, $orig_w, $orig_h );
if ( ! $proceed ) {
return false;
}
}
/*
* The return array matches the parameters to imagecopyresampled().
* int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
*/
return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
}
/**
* Resizes an image to make a thumbnail or intermediate size.
*
* The returned array has the file size, the image width, and image height. The
* {@see 'image_make_intermediate_size'} filter can be used to hook in and change the
* values of the returned array. The only parameter is the resized file path.
*
* @since 2.5.0
*
* @param string $file File path.
* @param int $width Image width.
* @param int $height Image height.
* @param bool|array $crop {
* Optional. Image cropping behavior. If false, the image will be scaled (default).
* If true, image will be cropped to the specified dimensions using center positions.
* If an array, the image will be cropped using the array to specify the crop location:
*
* @type string $0 The x crop position. Accepts 'left', 'center', or 'right'.
* @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'.
* }
* @return array|false Metadata array on success. False if no image was created.
*/
function image_make_intermediate_size( $file, $width, $height, $crop = false ) {
if ( $width || $height ) {
$editor = wp_get_image_editor( $file );
if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $width, $height, $crop ) ) ) {
return false;
}
$resized_file = $editor->save();
if ( ! is_wp_error( $resized_file ) && $resized_file ) {
unset( $resized_file['path'] );
return $resized_file;
}
}
return false;
}
/**
* Helper function to test if aspect ratios for two images match.
*
* @since 4.6.0
*
* @param int $source_width Width of the first image in pixels.
* @param int $source_height Height of the first image in pixels.
* @param int $target_width Width of the second image in pixels.
* @param int $target_height Height of the second image in pixels.
* @return bool True if aspect ratios match within 1px. False if not.
*/
function wp_image_matches_ratio( $source_width, $source_height, $target_width, $target_height ) {
/*
* To test for varying crops, we constrain the dimensions of the larger image
* to the dimensions of the smaller image and see if they match.
*/
if ( $source_width > $target_width ) {
$constrained_size = wp_constrain_dimensions( $source_width, $source_height, $target_width );
$expected_size = array( $target_width, $target_height );
} else {
$constrained_size = wp_constrain_dimensions( $target_width, $target_height, $source_width );
$expected_size = array( $source_width, $source_height );
}
// If the image dimensions are within 1px of the expected size, we consider it a match.
$matched = ( wp_fuzzy_number_match( $constrained_size[0], $expected_size[0] ) && wp_fuzzy_number_match( $constrained_size[1], $expected_size[1] ) );
return $matched;
}
/**
* Retrieves the image's intermediate size (resized) path, width, and height.
*
* The $size parameter can be an array with the width and height respectively.
* If the size matches the 'sizes' metadata array for width and height, then it
* will be used. If there is no direct match, then the nearest image size larger
* than the specified size will be used. If nothing is found, then the function
* will break out and return false.
*
* The metadata 'sizes' is used for compatible sizes that can be used for the
* parameter $size value.
*
* The url path will be given, when the $size parameter is a string.
*
* If you are passing an array for the $size, you should consider using
* add_image_size() so that a cropped version is generated. It's much more
* efficient than having to find the closest-sized image and then having the
* browser scale down the image.
*
* @since 2.5.0
*
* @param int $post_id Attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @return array|false {
* Array of file relative path, width, and height on success. Additionally includes absolute
* path and URL if registered size is passed to `$size` parameter. False on failure.
*
* @type string $file Filename of image.
* @type int $width Width of image in pixels.
* @type int $height Height of image in pixels.
* @type string $path Path of image relative to uploads directory.
* @type string $url URL of image.
* }
*/
function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) {
$imagedata = wp_get_attachment_metadata( $post_id );
if ( ! $size || ! is_array( $imagedata ) || empty( $imagedata['sizes'] ) ) {
return false;
}
$data = array();
// Find the best match when '$size' is an array.
if ( is_array( $size ) ) {
$candidates = array();
if ( ! isset( $imagedata['file'] ) && isset( $imagedata['sizes']['full'] ) ) {
$imagedata['height'] = $imagedata['sizes']['full']['height'];
$imagedata['width'] = $imagedata['sizes']['full']['width'];
}
foreach ( $imagedata['sizes'] as $_size => $data ) {
// If there's an exact match to an existing image size, short circuit.
if ( (int) $data['width'] === (int) $size[0] && (int) $data['height'] === (int) $size[1] ) {
$candidates[ $data['width'] * $data['height'] ] = $data;
break;
}
// If it's not an exact match, consider larger sizes with the same aspect ratio.
if ( $data['width'] >= $size[0] && $data['height'] >= $size[1] ) {
// If '0' is passed to either size, we test ratios against the original file.
if ( 0 === $size[0] || 0 === $size[1] ) {
$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $imagedata['width'], $imagedata['height'] );
} else {
$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $size[0], $size[1] );
}
if ( $same_ratio ) {
$candidates[ $data['width'] * $data['height'] ] = $data;
}
}
}
if ( ! empty( $candidates ) ) {
// Sort the array by size if we have more than one candidate.
if ( 1 < count( $candidates ) ) {
ksort( $candidates );
}
$data = array_shift( $candidates );
/*
* When the size requested is smaller than the thumbnail dimensions, we
* fall back to the thumbnail size to maintain backward compatibility with
* pre 4.6 versions of WordPress.
*/
} elseif ( ! empty( $imagedata['sizes']['thumbnail'] ) && $imagedata['sizes']['thumbnail']['width'] >= $size[0] && $imagedata['sizes']['thumbnail']['width'] >= $size[1] ) {
$data = $imagedata['sizes']['thumbnail'];
} else {
return false;
}
// Constrain the width and height attributes to the requested values.
list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
} elseif ( ! empty( $imagedata['sizes'][ $size ] ) ) {
$data = $imagedata['sizes'][ $size ];
}
// If we still don't have a match at this point, return false.
if ( empty( $data ) ) {
return false;
}
// Include the full filesystem path of the intermediate file.
if ( empty( $data['path'] ) && ! empty( $data['file'] ) && ! empty( $imagedata['file'] ) ) {
$file_url = wp_get_attachment_url( $post_id );
$data['path'] = path_join( dirname( $imagedata['file'] ), $data['file'] );
$data['url'] = path_join( dirname( $file_url ), $data['file'] );
}
/**
* Filters the output of image_get_intermediate_size()
*
* @since 4.4.0
*
* @see image_get_intermediate_size()
*
* @param array $data Array of file relative path, width, and height on success. May also include
* file absolute path and URL.
* @param int $post_id The ID of the image attachment.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
*/
return apply_filters( 'image_get_intermediate_size', $data, $post_id, $size );
}
/**
* Gets the available intermediate image size names.
*
* @since 3.0.0
*
* @return string[] An array of image size names.
*/
function get_intermediate_image_sizes() {
$default_sizes = array( 'thumbnail', 'medium', 'medium_large', 'large' );
$additional_sizes = wp_get_additional_image_sizes();
if ( ! empty( $additional_sizes ) ) {
$default_sizes = array_merge( $default_sizes, array_keys( $additional_sizes ) );
}
/**
* Filters the list of intermediate image sizes.
*
* @since 2.5.0
*
* @param string[] $default_sizes An array of intermediate image size names. Defaults
* are 'thumbnail', 'medium', 'medium_large', 'large'.
*/
return apply_filters( 'intermediate_image_sizes', $default_sizes );
}
/**
* Returns a normalized list of all currently registered image sub-sizes.
*
* @since 5.3.0
* @uses wp_get_additional_image_sizes()
* @uses get_intermediate_image_sizes()
*
* @return array[] Associative array of arrays of image sub-size information,
* keyed by image size name.
*/
function wp_get_registered_image_subsizes() {
$additional_sizes = wp_get_additional_image_sizes();
$all_sizes = array();
foreach ( get_intermediate_image_sizes() as $size_name ) {
$size_data = array(
'width' => 0,
'height' => 0,
'crop' => false,
);
if ( isset( $additional_sizes[ $size_name ]['width'] ) ) {
// For sizes added by plugins and themes.
$size_data['width'] = (int) $additional_sizes[ $size_name ]['width'];
} else {
// For default sizes set in options.
$size_data['width'] = (int) get_option( "{$size_name}_size_w" );
}
if ( isset( $additional_sizes[ $size_name ]['height'] ) ) {
$size_data['height'] = (int) $additional_sizes[ $size_name ]['height'];
} else {
$size_data['height'] = (int) get_option( "{$size_name}_size_h" );
}
if ( empty( $size_data['width'] ) && empty( $size_data['height'] ) ) {
// This size isn't set.
continue;
}
if ( isset( $additional_sizes[ $size_name ]['crop'] ) ) {
$size_data['crop'] = $additional_sizes[ $size_name ]['crop'];
} else {
$size_data['crop'] = get_option( "{$size_name}_crop" );
}
if ( ! is_array( $size_data['crop'] ) || empty( $size_data['crop'] ) ) {
$size_data['crop'] = (bool) $size_data['crop'];
}
$all_sizes[ $size_name ] = $size_data;
}
return $all_sizes;
}
/**
* Retrieves an image to represent an attachment.
*
* @since 2.5.0
*
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $icon Optional. Whether the image should fall back to a mime type icon. Default false.
* @return array|false {
* Array of image data, or boolean false if no image is available.
*
* @type string $0 Image source URL.
* @type int $1 Image width in pixels.
* @type int $2 Image height in pixels.
* @type bool $3 Whether the image is a resized image.
* }
*/
function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon = false ) {
// Get a thumbnail or intermediate image if there is one.
$image = image_downsize( $attachment_id, $size );
if ( ! $image ) {
$src = false;
if ( $icon ) {
$src = wp_mime_type_icon( $attachment_id, '.svg' );
if ( $src ) {
/** This filter is documented in wp-includes/post.php */
$icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
$src_file = $icon_dir . '/' . wp_basename( $src );
list( $width, $height ) = wp_getimagesize( $src_file );
$ext = strtolower( substr( $src_file, -4 ) );
if ( '.svg' === $ext ) {
// SVG does not have true dimensions, so this assigns width and height directly.
$width = 48;
$height = 64;
} else {
list( $width, $height ) = wp_getimagesize( $src_file );
}
}
}
if ( $src && $width && $height ) {
$image = array( $src, $width, $height, false );
}
}
/**
* Filters the attachment image source result.
*
* @since 4.3.0
*
* @param array|false $image {
* Array of image data, or boolean false if no image is available.
*
* @type string $0 Image source URL.
* @type int $1 Image width in pixels.
* @type int $2 Image height in pixels.
* @type bool $3 Whether the image is a resized image.
* }
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param bool $icon Whether the image should be treated as an icon.
*/
return apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon );
}
/**
* Gets an HTML img element representing an image attachment.
*
* While `$size` will accept an array, it is better to register a size with
* add_image_size() so that a cropped version is generated. It's much more
* efficient than having to find the closest-sized image and then having the
* browser scale down the image.
*
* @since 2.5.0
* @since 4.4.0 The `$srcset` and `$sizes` attributes were added.
* @since 5.5.0 The `$loading` attribute was added.
* @since 6.1.0 The `$decoding` attribute was added.
*
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $icon Optional. Whether the image should be treated as an icon. Default false.
* @param string|array $attr {
* Optional. Attributes for the image markup.
*
* @type string $src Image attachment URL.
* @type string $class CSS class name or space-separated list of classes.
* Default `attachment-$size_class size-$size_class`,
* where `$size_class` is the image size being requested.
* @type string $alt Image description for the alt attribute.
* @type string $srcset The 'srcset' attribute value.
* @type string $sizes The 'sizes' attribute value.
* @type string|false $loading The 'loading' attribute value. Passing a value of false
* will result in the attribute being omitted for the image.
* Default determined by {@see wp_get_loading_optimization_attributes()}.
* @type string $decoding The 'decoding' attribute value. Possible values are
* 'async' (default), 'sync', or 'auto'. Passing false or an empty
* string will result in the attribute being omitted.
* @type string $fetchpriority The 'fetchpriority' attribute value, whether `high`, `low`, or `auto`.
* Default determined by {@see wp_get_loading_optimization_attributes()}.
* }
* @return string HTML img element or empty string on failure.
*/
function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = false, $attr = '' ) {
$html = '';
$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
if ( $image ) {
list( $src, $width, $height ) = $image;
$attachment = get_post( $attachment_id );
$hwstring = image_hwstring( $width, $height );
$size_class = $size;
if ( is_array( $size_class ) ) {
$size_class = implode( 'x', $size_class );
}
$default_attr = array(
'src' => $src,
'class' => "attachment-$size_class size-$size_class",
'alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ),
);
/**
* Filters the context in which wp_get_attachment_image() is used.
*
* @since 6.3.0
*
* @param string $context The context. Default 'wp_get_attachment_image'.
*/
$context = apply_filters( 'wp_get_attachment_image_context', 'wp_get_attachment_image' );
$attr = wp_parse_args( $attr, $default_attr );
$loading_attr = $attr;
$loading_attr['width'] = $width;
$loading_attr['height'] = $height;
$loading_optimization_attr = wp_get_loading_optimization_attributes(
'img',
$loading_attr,
$context
);
// Add loading optimization attributes if not available.
$attr = array_merge( $attr, $loading_optimization_attr );
// Omit the `decoding` attribute if the value is invalid according to the spec.
if ( empty( $attr['decoding'] ) || ! in_array( $attr['decoding'], array( 'async', 'sync', 'auto' ), true ) ) {
unset( $attr['decoding'] );
}
/*
* If the default value of `lazy` for the `loading` attribute is overridden
* to omit the attribute for this image, ensure it is not included.
*/
if ( isset( $attr['loading'] ) && ! $attr['loading'] ) {
unset( $attr['loading'] );
}
// If the `fetchpriority` attribute is overridden and set to false or an empty string.
if ( isset( $attr['fetchpriority'] ) && ! $attr['fetchpriority'] ) {
unset( $attr['fetchpriority'] );
}
// Generate 'srcset' and 'sizes' if not already present.
if ( empty( $attr['srcset'] ) ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
if ( is_array( $image_meta ) ) {
$size_array = array( absint( $width ), absint( $height ) );
$srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id );
$sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id );
if ( $srcset && ( $sizes || ! empty( $attr['sizes'] ) ) ) {
$attr['srcset'] = $srcset;
if ( empty( $attr['sizes'] ) ) {
$attr['sizes'] = $sizes;
}
}
}
}
/** This filter is documented in wp-includes/media.php */
$add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true );
// Adds 'auto' to the sizes attribute if applicable.
if (
$add_auto_sizes &&
isset( $attr['loading'] ) &&
'lazy' === $attr['loading'] &&
isset( $attr['sizes'] ) &&
! wp_sizes_attribute_includes_valid_auto( $attr['sizes'] )
) {
$attr['sizes'] = 'auto, ' . $attr['sizes'];
}
/**
* Filters the list of attachment image attributes.
*
* @since 2.8.0
*
* @param string[] $attr Array of attribute values for the image markup, keyed by attribute name.
* See wp_get_attachment_image().
* @param WP_Post $attachment Image attachment post.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
*/
$attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $size );
$attr = array_map( 'esc_attr', $attr );
$html = rtrim( "<img $hwstring" );
foreach ( $attr as $name => $value ) {
$html .= " $name=" . '"' . $value . '"';
}
$html .= ' />';
}
/**
* Filters the HTML img element representing an image attachment.
*
* @since 5.6.0
*
* @param string $html HTML img element or empty string on failure.
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param bool $icon Whether the image should be treated as an icon.
* @param string[] $attr Array of attribute values for the image markup, keyed by attribute name.
* See wp_get_attachment_image().
*/
return apply_filters( 'wp_get_attachment_image', $html, $attachment_id, $size, $icon, $attr );
}
/**
* Gets the URL of an image attachment.
*
* @since 4.4.0
*
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $icon Optional. Whether the image should be treated as an icon. Default false.
* @return string|false Attachment URL or false if no image is available. If `$size` does not match
* any registered image size, the original image URL will be returned.
*/
function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon = false ) {
$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
return isset( $image[0] ) ? $image[0] : false;
}
/**
* Gets the attachment path relative to the upload directory.
*
* @since 4.4.1
* @access private
*
* @param string $file Attachment file name.
* @return string Attachment path relative to the upload directory.
*/
function _wp_get_attachment_relative_path( $file ) {
$dirname = dirname( $file );
if ( '.' === $dirname ) {
return '';
}
if ( str_contains( $dirname, 'wp-content/uploads' ) ) {
// Get the directory name relative to the upload directory (back compat for pre-2.7 uploads).
$dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 );
$dirname = ltrim( $dirname, '/' );
}
return $dirname;
}
/**
* Gets the image size as array from its meta data.
*
* Used for responsive images.
*
* @since 4.4.0
* @access private
*
* @param string $size_name Image size. Accepts any registered image size name.
* @param array $image_meta The image meta data.
* @return array|false {
* Array of width and height or false if the size isn't present in the meta data.
*
* @type int $0 Image width.
* @type int $1 Image height.
* }
*/
function _wp_get_image_size_from_meta( $size_name, $image_meta ) {
if ( 'full' === $size_name ) {
return array(
absint( $image_meta['width'] ),
absint( $image_meta['height'] ),
);
} elseif ( ! empty( $image_meta['sizes'][ $size_name ] ) ) {
return array(
absint( $image_meta['sizes'][ $size_name ]['width'] ),
absint( $image_meta['sizes'][ $size_name ]['height'] ),
);
}
return false;
}
/**
* Retrieves the value for an image attachment's 'srcset' attribute.
*
* @since 4.4.0
*
* @see wp_calculate_image_srcset()
*
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'medium'.
* @param array|null $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
* Default null.
* @return string|false A 'srcset' value string or false.
*/
function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) {
$image = wp_get_attachment_image_src( $attachment_id, $size );
if ( ! $image ) {
return false;
}
if ( ! is_array( $image_meta ) ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
}
$image_src = $image[0];
$size_array = array(
absint( $image[1] ),
absint( $image[2] ),
);
return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
}
/**
* A helper function to calculate the image sources to include in a 'srcset' attribute.
*
* @since 4.4.0
*
* @param int[] $size_array {
* An array of width and height values.
*
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* }
* @param string $image_src The 'src' of the image.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Optional. The image attachment ID. Default 0.
* @return string|false The 'srcset' attribute value. False on error or when only one source exists.
*/
function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
/**
* Pre-filters the image meta to be able to fix inconsistencies in the stored data.
*
* @since 4.5.0
*
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int[] $size_array {
* An array of requested width and height values.
*
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* }
* @param string $image_src The 'src' of the image.
* @param int $attachment_id The image attachment ID or 0 if not supplied.
*/
$image_meta = apply_filters( 'wp_calculate_image_srcset_meta', $image_meta, $size_array, $image_src, $attachment_id );
if ( empty( $image_meta['sizes'] ) || ! isset( $image_meta['file'] ) || strlen( $image_meta['file'] ) < 4 ) {
return false;
}
$image_sizes = $image_meta['sizes'];
// Get the width and height of the image.
$image_width = (int) $size_array[0];
$image_height = (int) $size_array[1];
// Bail early if error/no width.
if ( $image_width < 1 ) {
return false;
}
$image_basename = wp_basename( $image_meta['file'] );
/*
* WordPress flattens animated GIFs into one frame when generating intermediate sizes.
* To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
* If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
*/
if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
$image_sizes[] = array(
'width' => $image_meta['width'],
'height' => $image_meta['height'],
'file' => $image_basename,
);
} elseif ( str_contains( $image_src, $image_meta['file'] ) ) {
return false;
}
// Retrieve the uploads sub-directory from the full size image.
$dirname = _wp_get_attachment_relative_path( $image_meta['file'] );
if ( $dirname ) {
$dirname = trailingslashit( $dirname );
}
$upload_dir = wp_get_upload_dir();
$image_baseurl = trailingslashit( $upload_dir['baseurl'] ) . $dirname;
/*
* If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain
* (which is to say, when they share the domain name of the current request).
*/
if ( is_ssl() && ! str_starts_with( $image_baseurl, 'https' ) ) {
/*
* Since the `Host:` header might contain a port, it should
* be compared against the image URL using the same port.
*/
$parsed = parse_url( $image_baseurl );
$domain = isset( $parsed['host'] ) ? $parsed['host'] : '';
if ( isset( $parsed['port'] ) ) {
$domain .= ':' . $parsed['port'];
}
if ( $_SERVER['HTTP_HOST'] === $domain ) {
$image_baseurl = set_url_scheme( $image_baseurl, 'https' );
}
}
/*
* Images that have been edited in WordPress after being uploaded will
* contain a unique hash. Look for that hash and use it later to filter
* out images that are leftovers from previous versions.
*/
$image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );
/**
* Filters the maximum image width to be included in a 'srcset' attribute.
*
* @since 4.4.0
*
* @param int $max_width The maximum image width to be included in the 'srcset'. Default '2048'.
* @param int[] $size_array {
* An array of requested width and height values.
*
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* }
*/
$max_srcset_image_width = apply_filters( 'max_srcset_image_width', 2048, $size_array );
// Array to hold URL candidates.
$sources = array();
/**
* To make sure the ID matches our image src, we will check to see if any sizes in our attachment
* meta match our $image_src. If no matches are found we don't return a srcset to avoid serving
* an incorrect image. See #35045.
*/
$src_matched = false;
/*
* Loop through available images. Only use images that are resized
* versions of the same edit.
*/
foreach ( $image_sizes as $image ) {
$is_src = false;
// Check if image meta isn't corrupted.
if ( ! is_array( $image ) ) {
continue;
}
// If the file name is part of the `src`, we've confirmed a match.
if ( ! $src_matched && str_contains( $image_src, $dirname . $image['file'] ) ) {
$src_matched = true;
$is_src = true;
}
// Filter out images that are from previous edits.
if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
continue;
}
/*
* Filters out images that are wider than '$max_srcset_image_width' unless
* that file is in the 'src' attribute.
*/
if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width && ! $is_src ) {
continue;
}
// If the image dimensions are within 1px of the expected size, use it.
if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
// Add the URL, descriptor, and value to the sources array to be returned.
$source = array(
'url' => $image_baseurl . $image['file'],
'descriptor' => 'w',
'value' => $image['width'],
);
// The 'src' image has to be the first in the 'srcset', because of a bug in iOS8. See #35030.
if ( $is_src ) {
$sources = array( $image['width'] => $source ) + $sources;
} else {
$sources[ $image['width'] ] = $source;
}
}
}
/**
* Filters an image's 'srcset' sources.
*
* @since 4.4.0
*
* @param array $sources {
* One or more arrays of source data to include in the 'srcset'.
*
* @type array $width {
* @type string $url The URL of an image source.
* @type string $descriptor The descriptor type used in the image candidate string,
* either 'w' or 'x'.
* @type int $value The source width if paired with a 'w' descriptor, or a
* pixel density value if paired with an 'x' descriptor.
* }
* }
* @param array $size_array {
* An array of requested width and height values.
*
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* }
* @param string $image_src The 'src' of the image.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Image attachment ID or 0.
*/
$sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );
// Only return a 'srcset' value if there is more than one source.
if ( ! $src_matched || ! is_array( $sources ) || count( $sources ) < 2 ) {
return false;
}
$srcset = '';
foreach ( $sources as $source ) {
$srcset .= str_replace( ' ', '%20', $source['url'] ) . ' ' . $source['value'] . $source['descriptor'] . ', ';
}
return rtrim( $srcset, ', ' );
}
/**
* Retrieves the value for an image attachment's 'sizes' attribute.
*
* @since 4.4.0
*
* @see wp_calculate_image_sizes()
*
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'medium'.
* @param array|null $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
* Default null.
* @return string|false A valid source size value for use in a 'sizes' attribute or false.
*/
function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) {
$image = wp_get_attachment_image_src( $attachment_id, $size );
if ( ! $image ) {
return false;
}
if ( ! is_array( $image_meta ) ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
}
$image_src = $image[0];
$size_array = array(
absint( $image[1] ),
absint( $image[2] ),
);
return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
}
/**
* Creates a 'sizes' attribute value for an image.
*
* @since 4.4.0
*
* @param string|int[] $size Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order).
* @param string|null $image_src Optional. The URL to the image file. Default null.
* @param array|null $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
* Default null.
* @param int $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id`
* is needed when using the image size name as argument for `$size`. Default 0.
* @return string|false A valid source size value for use in a 'sizes' attribute or false.
*/
function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0 ) {
$width = 0;
if ( is_array( $size ) ) {
$width = absint( $size[0] );
} elseif ( is_string( $size ) ) {
if ( ! $image_meta && $attachment_id ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
}
if ( is_array( $image_meta ) ) {
$size_array = _wp_get_image_size_from_meta( $size, $image_meta );
if ( $size_array ) {
$width = absint( $size_array[0] );
}
}
}
if ( ! $width ) {
return false;
}
// Setup the default 'sizes' attribute.
$sizes = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width );
/**
* Filters the output of 'wp_calculate_image_sizes()'.
*
* @since 4.4.0
*
* @param string $sizes A source size value for use in a 'sizes' attribute.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param string|null $image_src The URL to the image file or null.
* @param array|null $image_meta The image meta data as returned by wp_get_attachment_metadata() or null.
* @param int $attachment_id Image attachment ID of the original image or 0.
*/
return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id );
}
/**
* Determines if the image meta data is for the image source file.
*
* The image meta data is retrieved by attachment post ID. In some cases the post IDs may change.
* For example when the website is exported and imported at another website. Then the
* attachment post IDs that are in post_content for the exported website may not match
* the same attachments at the new website.
*
* @since 5.5.0
*
* @param string $image_location The full path or URI to the image file.
* @param array $image_meta The attachment meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Optional. The image attachment ID. Default 0.
* @return bool Whether the image meta is for this image file.
*/
function wp_image_file_matches_image_meta( $image_location, $image_meta, $attachment_id = 0 ) {
$match = false;
// Ensure the $image_meta is valid.
if ( isset( $image_meta['file'] ) && strlen( $image_meta['file'] ) > 4 ) {
// Remove query args in image URI.
list( $image_location ) = explode( '?', $image_location );
// Check if the relative image path from the image meta is at the end of $image_location.
if ( strrpos( $image_location, $image_meta['file'] ) === strlen( $image_location ) - strlen( $image_meta['file'] ) ) {
$match = true;
} else {
// Retrieve the uploads sub-directory from the full size image.
$dirname = _wp_get_attachment_relative_path( $image_meta['file'] );
if ( $dirname ) {
$dirname = trailingslashit( $dirname );
}
if ( ! empty( $image_meta['original_image'] ) ) {
$relative_path = $dirname . $image_meta['original_image'];
if ( strrpos( $image_location, $relative_path ) === strlen( $image_location ) - strlen( $relative_path ) ) {
$match = true;
}
}
if ( ! $match && ! empty( $image_meta['sizes'] ) ) {
foreach ( $image_meta['sizes'] as $image_size_data ) {
$relative_path = $dirname . $image_size_data['file'];
if ( strrpos( $image_location, $relative_path ) === strlen( $image_location ) - strlen( $relative_path ) ) {
$match = true;
break;
}
}
}
}
}
/**
* Filters whether an image path or URI matches image meta.
*
* @since 5.5.0
*
* @param bool $match Whether the image relative path from the image meta
* matches the end of the URI or path to the image file.
* @param string $image_location Full path or URI to the tested image file.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id The image attachment ID or 0 if not supplied.
*/
return apply_filters( 'wp_image_file_matches_image_meta', $match, $image_location, $image_meta, $attachment_id );
}
/**
* Determines an image's width and height dimensions based on the source file.
*
* @since 5.5.0
*
* @param string $image_src The image source file.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Optional. The image attachment ID. Default 0.
* @return array|false Array with first element being the width and second element being the height,
* or false if dimensions cannot be determined.
*/
function wp_image_src_get_dimensions( $image_src, $image_meta, $attachment_id = 0 ) {
$dimensions = false;
// Is it a full size image?
if (
isset( $image_meta['file'] ) &&
str_contains( $image_src, wp_basename( $image_meta['file'] ) )
) {
$dimensions = array(
(int) $image_meta['width'],
(int) $image_meta['height'],
);
}
if ( ! $dimensions && ! empty( $image_meta['sizes'] ) ) {
$src_filename = wp_basename( $image_src );
foreach ( $image_meta['sizes'] as $image_size_data ) {
if ( $src_filename === $image_size_data['file'] ) {
$dimensions = array(
(int) $image_size_data['width'],
(int) $image_size_data['height'],
);
break;
}
}
}
/**
* Filters the 'wp_image_src_get_dimensions' value.
*
* @since 5.7.0
*
* @param array|false $dimensions Array with first element being the width
* and second element being the height, or
* false if dimensions could not be determined.
* @param string $image_src The image source file.
* @param array $image_meta The image meta data as returned by
* 'wp_get_attachment_metadata()'.
* @param int $attachment_id The image attachment ID. Default 0.
*/
return apply_filters( 'wp_image_src_get_dimensions', $dimensions, $image_src, $image_meta, $attachment_id );
}
/**
* Adds 'srcset' and 'sizes' attributes to an existing 'img' element.
*
* @since 4.4.0
*
* @see wp_calculate_image_srcset()
* @see wp_calculate_image_sizes()
*
* @param string $image An HTML 'img' element to be filtered.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Image attachment ID.
* @return string Converted 'img' element with 'srcset' and 'sizes' attributes added.
*/
function wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ) {
// Ensure the image meta exists.
if ( empty( $image_meta['sizes'] ) ) {
return $image;
}
$image_src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : '';
list( $image_src ) = explode( '?', $image_src );
// Return early if we couldn't get the image source.
if ( ! $image_src ) {
return $image;
}
// Bail early if an image has been inserted and later edited.
if ( preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash )
&& ! str_contains( wp_basename( $image_src ), $img_edit_hash[0] )
) {
return $image;
}
$width = preg_match( '/ width="([0-9]+)"/', $image, $match_width ) ? (int) $match_width[1] : 0;
$height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : 0;
if ( $width && $height ) {
$size_array = array( $width, $height );
} else {
$size_array = wp_image_src_get_dimensions( $image_src, $image_meta, $attachment_id );
if ( ! $size_array ) {
return $image;
}
}
$srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
if ( $srcset ) {
// Check if there is already a 'sizes' attribute.
$sizes = strpos( $image, ' sizes=' );
if ( ! $sizes ) {
$sizes = wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
}
}
if ( $srcset && $sizes ) {
// Format the 'srcset' and 'sizes' string and escape attributes.
$attr = sprintf( ' srcset="%s"', esc_attr( $srcset ) );
if ( is_string( $sizes ) ) {
$attr .= sprintf( ' sizes="%s"', esc_attr( $sizes ) );
}
// Add the srcset and sizes attributes to the image markup.
return preg_replace( '/<img ([^>]+?)[\/ ]*>/', '<img $1' . $attr . ' />', $image );
}
return $image;
}
/**
* Determines whether to add the `loading` attribute to the specified tag in the specified context.
*
* @since 5.5.0
* @since 5.7.0 Now returns `true` by default for `iframe` tags.
*
* @param string $tag_name The tag name.
* @param string $context Additional context, like the current filter name
* or the function name from where this was called.
* @return bool Whether to add the attribute.
*/
function wp_lazy_loading_enabled( $tag_name, $context ) {
/*
* By default add to all 'img' and 'iframe' tags.
* See https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading
* See https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-loading
*/
$default = ( 'img' === $tag_name || 'iframe' === $tag_name );
/**
* Filters whether to add the `loading` attribute to the specified tag in the specified context.
*
* @since 5.5.0
*
* @param bool $default Default value.
* @param string $tag_name The tag name.
* @param string $context Additional context, like the current filter name
* or the function name from where this was called.
*/
return (bool) apply_filters( 'wp_lazy_loading_enabled', $default, $tag_name, $context );
}
/**
* Filters specific tags in post content and modifies their markup.
*
* Modifies HTML tags in post content to include new browser and HTML technologies
* that may not have existed at the time of post creation. These modifications currently
* include adding `srcset`, `sizes`, and `loading` attributes to `img` HTML tags, as well
* as adding `loading` attributes to `iframe` HTML tags.
* Future similar optimizations should be added/expected here.
*
* @since 5.5.0
* @since 5.7.0 Now supports adding `loading` attributes to `iframe` tags.
*
* @see wp_img_tag_add_width_and_height_attr()
* @see wp_img_tag_add_srcset_and_sizes_attr()
* @see wp_img_tag_add_loading_optimization_attrs()
* @see wp_iframe_tag_add_loading_attr()
*
* @param string $content The HTML content to be filtered.
* @param string $context Optional. Additional context to pass to the filters.
* Defaults to `current_filter()` when not set.
* @return string Converted content with images modified.
*/
function wp_filter_content_tags( $content, $context = null ) {
if ( null === $context ) {
$context = current_filter();
}
$add_iframe_loading_attr = wp_lazy_loading_enabled( 'iframe', $context );
if ( ! preg_match_all( '/<(img|iframe)\s[^>]+>/', $content, $matches, PREG_SET_ORDER ) ) {
return $content;
}
// List of the unique `img` tags found in $content.
$images = array();
// List of the unique `iframe` tags found in $content.
$iframes = array();
foreach ( $matches as $match ) {
list( $tag, $tag_name ) = $match;
switch ( $tag_name ) {
case 'img':
if ( preg_match( '/wp-image-([0-9]+)/i', $tag, $class_id ) ) {
$attachment_id = absint( $class_id[1] );
if ( $attachment_id ) {
/*
* If exactly the same image tag is used more than once, overwrite it.
* All identical tags will be replaced later with 'str_replace()'.
*/
$images[ $tag ] = $attachment_id;
break;
}
}
$images[ $tag ] = 0;
break;
case 'iframe':
$iframes[ $tag ] = 0;
break;
}
}
// Reduce the array to unique attachment IDs.
$attachment_ids = array_unique( array_filter( array_values( $images ) ) );
if ( count( $attachment_ids ) > 1 ) {
/*
* Warm the object cache with post and meta information for all found
* images to avoid making individual database calls.
*/
_prime_post_caches( $attachment_ids, false, true );
}
// Iterate through the matches in order of occurrence as it is relevant for whether or not to lazy-load.
foreach ( $matches as $match ) {
// Filter an image match.
if ( isset( $images[ $match[0] ] ) ) {
$filtered_image = $match[0];
$attachment_id = $images[ $match[0] ];
// Add 'width' and 'height' attributes if applicable.
if ( $attachment_id > 0 && ! str_contains( $filtered_image, ' width=' ) && ! str_contains( $filtered_image, ' height=' ) ) {
$filtered_image = wp_img_tag_add_width_and_height_attr( $filtered_image, $context, $attachment_id );
}
// Add 'srcset' and 'sizes' attributes if applicable.
if ( $attachment_id > 0 && ! str_contains( $filtered_image, ' srcset=' ) ) {
$filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id );
}
// Add loading optimization attributes if applicable.
$filtered_image = wp_img_tag_add_loading_optimization_attrs( $filtered_image, $context );
// Adds 'auto' to the sizes attribute if applicable.
$filtered_image = wp_img_tag_add_auto_sizes( $filtered_image );
/**
* Filters an img tag within the content for a given context.
*
* @since 6.0.0
*
* @param string $filtered_image Full img tag with attributes that will replace the source img tag.
* @param string $context Additional context, like the current filter name or the function name from where this was called.
* @param int $attachment_id The image attachment ID. May be 0 in case the image is not an attachment.
*/
$filtered_image = apply_filters( 'wp_content_img_tag', $filtered_image, $context, $attachment_id );
if ( $filtered_image !== $match[0] ) {
$content = str_replace( $match[0], $filtered_image, $content );
}
/*
* Unset image lookup to not run the same logic again unnecessarily if the same image tag is used more than
* once in the same blob of content.
*/
unset( $images[ $match[0] ] );
}
// Filter an iframe match.
if ( isset( $iframes[ $match[0] ] ) ) {
$filtered_iframe = $match[0];
// Add 'loading' attribute if applicable.
if ( $add_iframe_loading_attr && ! str_contains( $filtered_iframe, ' loading=' ) ) {
$filtered_iframe = wp_iframe_tag_add_loading_attr( $filtered_iframe, $context );
}
if ( $filtered_iframe !== $match[0] ) {
$content = str_replace( $match[0], $filtered_iframe, $content );
}
/*
* Unset iframe lookup to not run the same logic again unnecessarily if the same iframe tag is used more
* than once in the same blob of content.
*/
unset( $iframes[ $match[0] ] );
}
}
return $content;
}
/**
* Adds 'auto' to the sizes attribute to the image, if the image is lazy loaded and does not already include it.
*
* @since 6.7.0
*
* @param string $image The image tag markup being filtered.
* @return string The filtered image tag markup.
*/
function wp_img_tag_add_auto_sizes( string $image ): string {
/**
* Filters whether auto-sizes for lazy loaded images is enabled.
*
* @since 6.7.1
*
* @param boolean $enabled Whether auto-sizes for lazy loaded images is enabled.
*/
if ( ! apply_filters( 'wp_img_tag_add_auto_sizes', true ) ) {
return $image;
}
$processor = new WP_HTML_Tag_Processor( $image );
// Bail if there is no IMG tag.
if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) {
return $image;
}
// Bail early if the image is not lazy-loaded.
$loading = $processor->get_attribute( 'loading' );
if ( ! is_string( $loading ) || 'lazy' !== strtolower( trim( $loading, " \t\f\r\n" ) ) ) {
return $image;
}
/*
* Bail early if the image doesn't have a width attribute.
* Per WordPress Core itself, lazy-loaded images should always have a width attribute.
* However, it is possible that lazy-loading could be added by a plugin, where we don't have that guarantee.
* As such, it still makes sense to ensure presence of a width attribute here in order to use `sizes=auto`.
*/
$width = $processor->get_attribute( 'width' );
if ( ! is_string( $width ) || '' === $width ) {
return $image;
}
$sizes = $processor->get_attribute( 'sizes' );
// Bail early if the image is not responsive.
if ( ! is_string( $sizes ) ) {
return $image;
}
// Don't add 'auto' to the sizes attribute if it already exists.
if ( wp_sizes_attribute_includes_valid_auto( $sizes ) ) {
return $image;
}
$processor->set_attribute( 'sizes', "auto, $sizes" );
return $processor->get_updated_html();
}
/**
* Checks whether the given 'sizes' attribute includes the 'auto' keyword as the first item in the list.
*
* Per the HTML spec, if present it must be the first entry.
*
* @since 6.7.0
*
* @param string $sizes_attr The 'sizes' attribute value.
* @return bool True if the 'auto' keyword is present, false otherwise.
*/
function wp_sizes_attribute_includes_valid_auto( string $sizes_attr ): bool {
list( $first_size ) = explode( ',', $sizes_attr, 2 );
return 'auto' === strtolower( trim( $first_size, " \t\f\r\n" ) );
}
/**
* Prints a CSS rule to fix potential visual issues with images using `sizes=auto`.
*
* This rule overrides the similar rule in the default user agent stylesheet, to avoid images that use e.g.
* `width: auto` or `width: fit-content` to appear smaller.
*
* @since 6.7.1
* @see https://html.spec.whatwg.org/multipage/rendering.html#img-contain-size
* @see https://core.trac.wordpress.org/ticket/62413
*/
function wp_print_auto_sizes_contain_css_fix() {
/** This filter is documented in wp-includes/media.php */
$add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true );
if ( ! $add_auto_sizes ) {
return;
}
?>
<style>img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }</style>
<?php
}
/**
* Adds optimization attributes to an `img` HTML tag.
*
* @since 6.3.0
*
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @return string Converted `img` tag with optimization attributes added.
*/
function wp_img_tag_add_loading_optimization_attrs( $image, $context ) {
$src = preg_match( '/ src=["\']?([^"\']*)/i', $image, $matche_src ) ? $matche_src[1] : null;
$width = preg_match( '/ width=["\']([0-9]+)["\']/', $image, $match_width ) ? (int) $match_width[1] : null;
$height = preg_match( '/ height=["\']([0-9]+)["\']/', $image, $match_height ) ? (int) $match_height[1] : null;
$loading_val = preg_match( '/ loading=["\']([A-Za-z]+)["\']/', $image, $match_loading ) ? $match_loading[1] : null;
$fetchpriority_val = preg_match( '/ fetchpriority=["\']([A-Za-z]+)["\']/', $image, $match_fetchpriority ) ? $match_fetchpriority[1] : null;
$decoding_val = preg_match( '/ decoding=["\']([A-Za-z]+)["\']/', $image, $match_decoding ) ? $match_decoding[1] : null;
/*
* Get loading optimization attributes to use.
* This must occur before the conditional check below so that even images
* that are ineligible for being lazy-loaded are considered.
*/
$optimization_attrs = wp_get_loading_optimization_attributes(
'img',
array(
'src' => $src,
'width' => $width,
'height' => $height,
'loading' => $loading_val,
'fetchpriority' => $fetchpriority_val,
'decoding' => $decoding_val,
),
$context
);
// Images should have source for the loading optimization attributes to be added.
if ( ! str_contains( $image, ' src="' ) ) {
return $image;
}
if ( empty( $decoding_val ) ) {
/**
* Filters the `decoding` attribute value to add to an image. Default `async`.
*
* Returning a falsey value will omit the attribute.
*
* @since 6.1.0
*
* @param string|false|null $value The `decoding` attribute value. Returning a falsey value
* will result in the attribute being omitted for the image.
* Otherwise, it may be: 'async', 'sync', or 'auto'. Defaults to false.
* @param string $image The HTML `img` tag to be filtered.
* @param string $context Additional context about how the function was called
* or where the img tag is.
*/
$filtered_decoding_attr = apply_filters(
'wp_img_tag_add_decoding_attr',
isset( $optimization_attrs['decoding'] ) ? $optimization_attrs['decoding'] : false,
$image,
$context
);
// Validate the values after filtering.
if ( isset( $optimization_attrs['decoding'] ) && ! $filtered_decoding_attr ) {
// Unset `decoding` attribute if `$filtered_decoding_attr` is set to `false`.
unset( $optimization_attrs['decoding'] );
} elseif ( in_array( $filtered_decoding_attr, array( 'async', 'sync', 'auto' ), true ) ) {
$optimization_attrs['decoding'] = $filtered_decoding_attr;
}
if ( ! empty( $optimization_attrs['decoding'] ) ) {
$image = str_replace( '<img', '<img decoding="' . esc_attr( $optimization_attrs['decoding'] ) . '"', $image );
}
}
// Images should have dimension attributes for the 'loading' and 'fetchpriority' attributes to be added.
if ( ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) {
return $image;
}
// Retained for backward compatibility.
$loading_attrs_enabled = wp_lazy_loading_enabled( 'img', $context );
if ( empty( $loading_val ) && $loading_attrs_enabled ) {
/**
* Filters the `loading` attribute value to add to an image. Default `lazy`.
*
* Returning `false` or an empty string will not add the attribute.
* Returning `true` will add the default value.
*
* @since 5.5.0
*
* @param string|bool $value The `loading` attribute value. Returning a falsey value will result in
* the attribute being omitted for the image.
* @param string $image The HTML `img` tag to be filtered.
* @param string $context Additional context about how the function was called or where the img tag is.
*/
$filtered_loading_attr = apply_filters(
'wp_img_tag_add_loading_attr',
isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false,
$image,
$context
);
// Validate the values after filtering.
if ( isset( $optimization_attrs['loading'] ) && ! $filtered_loading_attr ) {
// Unset `loading` attributes if `$filtered_loading_attr` is set to `false`.
unset( $optimization_attrs['loading'] );
} elseif ( in_array( $filtered_loading_attr, array( 'lazy', 'eager' ), true ) ) {
/*
* If the filter changed the loading attribute to "lazy" when a fetchpriority attribute
* with value "high" is already present, trigger a warning since those two attribute
* values should be mutually exclusive.
*
* The same warning is present in `wp_get_loading_optimization_attributes()`, and here it
* is only intended for the specific scenario where the above filtered caused the problem.
*/
if ( isset( $optimization_attrs['fetchpriority'] ) && 'high' === $optimization_attrs['fetchpriority'] &&
( isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false ) !== $filtered_loading_attr &&
'lazy' === $filtered_loading_attr
) {
_doing_it_wrong(
__FUNCTION__,
__( 'An image should not be lazy-loaded and marked as high priority at the same time.' ),
'6.3.0'
);
}
// The filtered value will still be respected.
$optimization_attrs['loading'] = $filtered_loading_attr;
}
if ( ! empty( $optimization_attrs['loading'] ) ) {
$image = str_replace( '<img', '<img loading="' . esc_attr( $optimization_attrs['loading'] ) . '"', $image );
}
}
if ( empty( $fetchpriority_val ) && ! empty( $optimization_attrs['fetchpriority'] ) ) {
$image = str_replace( '<img', '<img fetchpriority="' . esc_attr( $optimization_attrs['fetchpriority'] ) . '"', $image );
}
return $image;
}
/**
* Adds `width` and `height` attributes to an `img` HTML tag.
*
* @since 5.5.0
*
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @param int $attachment_id Image attachment ID.
* @return string Converted 'img' element with 'width' and 'height' attributes added.
*/
function wp_img_tag_add_width_and_height_attr( $image, $context, $attachment_id ) {
$image_src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : '';
list( $image_src ) = explode( '?', $image_src );
// Return early if we couldn't get the image source.
if ( ! $image_src ) {
return $image;
}
/**
* Filters whether to add the missing `width` and `height` HTML attributes to the img tag. Default `true`.
*
* Returning anything else than `true` will not add the attributes.
*
* @since 5.5.0
*
* @param bool $value The filtered value, defaults to `true`.
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context about how the function was called or where the img tag is.
* @param int $attachment_id The image attachment ID.
*/
$add = apply_filters( 'wp_img_tag_add_width_and_height_attr', true, $image, $context, $attachment_id );
if ( true === $add ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
$size_array = wp_image_src_get_dimensions( $image_src, $image_meta, $attachment_id );
if ( $size_array && $size_array[0] && $size_array[1] ) {
// If the width is enforced through style (e.g. in an inline image), calculate the dimension attributes.
$style_width = preg_match( '/style="width:\s*(\d+)px;"/', $image, $match_width ) ? (int) $match_width[1] : 0;
if ( $style_width ) {
$size_array[1] = (int) round( $size_array[1] * $style_width / $size_array[0] );
$size_array[0] = $style_width;
}
$hw = trim( image_hwstring( $size_array[0], $size_array[1] ) );
return str_replace( '<img', "<img {$hw}", $image );
}
}
return $image;
}
/**
* Adds `srcset` and `sizes` attributes to an existing `img` HTML tag.
*
* @since 5.5.0
*
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @param int $attachment_id Image attachment ID.
* @return string Converted 'img' element with 'loading' attribute added.
*/
function wp_img_tag_add_srcset_and_sizes_attr( $image, $context, $attachment_id ) {
/**
* Filters whether to add the `srcset` and `sizes` HTML attributes to the img tag. Default `true`.
*
* Returning anything else than `true` will not add the attributes.
*
* @since 5.5.0
*
* @param bool $value The filtered value, defaults to `true`.
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context about how the function was called or where the img tag is.
* @param int $attachment_id The image attachment ID.
*/
$add = apply_filters( 'wp_img_tag_add_srcset_and_sizes_attr', true, $image, $context, $attachment_id );
if ( true === $add ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
return wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id );
}
return $image;
}
/**
* Adds `loading` attribute to an `iframe` HTML tag.
*
* @since 5.7.0
*
* @param string $iframe The HTML `iframe` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @return string Converted `iframe` tag with `loading` attribute added.
*/
function wp_iframe_tag_add_loading_attr( $iframe, $context ) {
/*
* Get loading attribute value to use. This must occur before the conditional check below so that even iframes that
* are ineligible for being lazy-loaded are considered.
*/
$optimization_attrs = wp_get_loading_optimization_attributes(
'iframe',
array(
/*
* The concrete values for width and height are not important here for now
* since fetchpriority is not yet supported for iframes.
* TODO: Use WP_HTML_Tag_Processor to extract actual values once support is
* added.
*/
'width' => str_contains( $iframe, ' width="' ) ? 100 : null,
'height' => str_contains( $iframe, ' height="' ) ? 100 : null,
// This function is never called when a 'loading' attribute is already present.
'loading' => null,
),
$context
);
// Iframes should have source and dimension attributes for the `loading` attribute to be added.
if ( ! str_contains( $iframe, ' src="' ) || ! str_contains( $iframe, ' width="' ) || ! str_contains( $iframe, ' height="' ) ) {
return $iframe;
}
$value = isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false;
/**
* Filters the `loading` attribute value to add to an iframe. Default `lazy`.
*
* Returning `false` or an empty string will not add the attribute.
* Returning `true` will add the default value.
*
* @since 5.7.0
*
* @param string|bool $value The `loading` attribute value. Returning a falsey value will result in
* the attribute being omitted for the iframe.
* @param string $iframe The HTML `iframe` tag to be filtered.
* @param string $context Additional context about how the function was called or where the iframe tag is.
*/
$value = apply_filters( 'wp_iframe_tag_add_loading_attr', $value, $iframe, $context );
if ( $value ) {
if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) {
$value = 'lazy';
}
return str_replace( '<iframe', '<iframe loading="' . esc_attr( $value ) . '"', $iframe );
}
return $iframe;
}
/**
* Adds a 'wp-post-image' class to post thumbnails. Internal use only.
*
* Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
* action hooks to dynamically add/remove itself so as to only filter post thumbnails.
*
* @ignore
* @since 2.9.0
*
* @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name.
* @return string[] Modified array of attributes including the new 'wp-post-image' class.
*/
function _wp_post_thumbnail_class_filter( $attr ) {
$attr['class'] .= ' wp-post-image';
return $attr;
}
/**
* Adds '_wp_post_thumbnail_class_filter' callback to the 'wp_get_attachment_image_attributes'
* filter hook. Internal use only.
*
* @ignore
* @since 2.9.0
*
* @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name.
*/
function _wp_post_thumbnail_class_filter_add( $attr ) {
add_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
}
/**
* Removes the '_wp_post_thumbnail_class_filter' callback from the 'wp_get_attachment_image_attributes'
* filter hook. Internal use only.
*
* @ignore
* @since 2.9.0
*
* @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name.
*/
function _wp_post_thumbnail_class_filter_remove( $attr ) {
remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
}
/**
* Overrides the context used in {@see wp_get_attachment_image()}. Internal use only.
*
* Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
* action hooks to dynamically add/remove itself so as to only filter post thumbnails.
*
* @ignore
* @since 6.3.0
* @access private
*
* @param string $context The context for rendering an attachment image.
* @return string Modified context set to 'the_post_thumbnail'.
*/
function _wp_post_thumbnail_context_filter( $context ) {
return 'the_post_thumbnail';
}
/**
* Adds the '_wp_post_thumbnail_context_filter' callback to the 'wp_get_attachment_image_context'
* filter hook. Internal use only.
*
* @ignore
* @since 6.3.0
* @access private
*/
function _wp_post_thumbnail_context_filter_add() {
add_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' );
}
/**
* Removes the '_wp_post_thumbnail_context_filter' callback from the 'wp_get_attachment_image_context'
* filter hook. Internal use only.
*
* @ignore
* @since 6.3.0
* @access private
*/
function _wp_post_thumbnail_context_filter_remove() {
remove_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' );
}
add_shortcode( 'wp_caption', 'img_caption_shortcode' );
add_shortcode( 'caption', 'img_caption_shortcode' );
/**
* Builds the Caption shortcode output.
*
* Allows a plugin to replace the content that would otherwise be returned. The
* filter is {@see 'img_caption_shortcode'} and passes an empty string, the attr
* parameter and the content parameter values.
*
* The supported attributes for the shortcode are 'id', 'caption_id', 'align',
* 'width', 'caption', and 'class'.
*
* @since 2.6.0
* @since 3.9.0 The `class` attribute was added.
* @since 5.1.0 The `caption_id` attribute was added.
* @since 5.9.0 The `$content` parameter default value changed from `null` to `''`.
*
* @param array $attr {
* Attributes of the caption shortcode.
*
* @type string $id ID of the image and caption container element, i.e. `<figure>` or `<div>`.
* @type string $caption_id ID of the caption element, i.e. `<figcaption>` or `<p>`.
* @type string $align Class name that aligns the caption. Default 'alignnone'. Accepts 'alignleft',
* 'aligncenter', alignright', 'alignnone'.
* @type int $width The width of the caption, in pixels.
* @type string $caption The caption text.
* @type string $class Additional class name(s) added to the caption container.
* }
* @param string $content Optional. Shortcode content. Default empty string.
* @return string HTML content to display the caption.
*/
function img_caption_shortcode( $attr, $content = '' ) {
// New-style shortcode with the caption inside the shortcode with the link and image tags.
if ( ! isset( $attr['caption'] ) ) {
if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
$content = $matches[1];
$attr['caption'] = trim( $matches[2] );
}
} elseif ( str_contains( $attr['caption'], '<' ) ) {
$attr['caption'] = wp_kses( $attr['caption'], 'post' );
}
/**
* Filters the default caption shortcode output.
*
* If the filtered output isn't empty, it will be used instead of generating
* the default caption template.
*
* @since 2.6.0
*
* @see img_caption_shortcode()
*
* @param string $output The caption output. Default empty.
* @param array $attr Attributes of the caption shortcode.
* @param string $content The image element, possibly wrapped in a hyperlink.
*/
$output = apply_filters( 'img_caption_shortcode', '', $attr, $content );
if ( ! empty( $output ) ) {
return $output;
}
$atts = shortcode_atts(
array(
'id' => '',
'caption_id' => '',
'align' => 'alignnone',
'width' => '',
'caption' => '',
'class' => '',
),
$attr,
'caption'
);
$atts['width'] = (int) $atts['width'];
if ( $atts['width'] < 1 || empty( $atts['caption'] ) ) {
return $content;
}
$id = '';
$caption_id = '';
$describedby = '';
if ( $atts['id'] ) {
$atts['id'] = sanitize_html_class( $atts['id'] );
$id = 'id="' . esc_attr( $atts['id'] ) . '" ';
}
if ( $atts['caption_id'] ) {
$atts['caption_id'] = sanitize_html_class( $atts['caption_id'] );
} elseif ( $atts['id'] ) {
$atts['caption_id'] = 'caption-' . str_replace( '_', '-', $atts['id'] );
}
if ( $atts['caption_id'] ) {
$caption_id = 'id="' . esc_attr( $atts['caption_id'] ) . '" ';
$describedby = 'aria-describedby="' . esc_attr( $atts['caption_id'] ) . '" ';
}
$class = trim( 'wp-caption ' . $atts['align'] . ' ' . $atts['class'] );
$html5 = current_theme_supports( 'html5', 'caption' );
// HTML5 captions never added the extra 10px to the image width.
$width = $html5 ? $atts['width'] : ( 10 + $atts['width'] );
/**
* Filters the width of an image's caption.
*
* By default, the caption is 10 pixels greater than the width of the image,
* to prevent post content from running up against a floated image.
*
* @since 3.7.0
*
* @see img_caption_shortcode()
*
* @param int $width Width of the caption in pixels. To remove this inline style,
* return zero.
* @param array $atts Attributes of the caption shortcode.
* @param string $content The image element, possibly wrapped in a hyperlink.
*/
$caption_width = apply_filters( 'img_caption_shortcode_width', $width, $atts, $content );
$style = '';
if ( $caption_width ) {
$style = 'style="width: ' . (int) $caption_width . 'px" ';
}
if ( $html5 ) {
$html = sprintf(
'<figure %s%s%sclass="%s">%s%s</figure>',
$id,
$describedby,
$style,
esc_attr( $class ),
do_shortcode( $content ),
sprintf(
'<figcaption %sclass="wp-caption-text">%s</figcaption>',
$caption_id,
$atts['caption']
)
);
} else {
$html = sprintf(
'<div %s%sclass="%s">%s%s</div>',
$id,
$style,
esc_attr( $class ),
str_replace( '<img ', '<img ' . $describedby, do_shortcode( $content ) ),
sprintf(
'<p %sclass="wp-caption-text">%s</p>',
$caption_id,
$atts['caption']
)
);
}
return $html;
}
add_shortcode( 'gallery', 'gallery_shortcode' );
/**
* Builds the Gallery shortcode output.
*
* This implements the functionality of the Gallery Shortcode for displaying
* WordPress images on a post.
*
* @since 2.5.0
* @since 2.8.0 Added the `$attr` parameter to set the shortcode output. New attributes included
* such as `size`, `itemtag`, `icontag`, `captiontag`, and columns. Changed markup from
* `div` tags to `dl`, `dt` and `dd` tags. Support more than one gallery on the
* same page.
* @since 2.9.0 Added support for `include` and `exclude` to shortcode.
* @since 3.5.0 Use get_post() instead of global `$post`. Handle mapping of `ids` to `include`
* and `orderby`.
* @since 3.6.0 Added validation for tags used in gallery shortcode. Add orientation information to items.
* @since 3.7.0 Introduced the `link` attribute.
* @since 3.9.0 `html5` gallery support, accepting 'itemtag', 'icontag', and 'captiontag' attributes.
* @since 4.0.0 Removed use of `extract()`.
* @since 4.1.0 Added attribute to `wp_get_attachment_link()` to output `aria-describedby`.
* @since 4.2.0 Passed the shortcode instance ID to `post_gallery` and `post_playlist` filters.
* @since 4.6.0 Standardized filter docs to match documentation standards for PHP.
* @since 5.1.0 Code cleanup for WPCS 1.0.0 coding standards.
* @since 5.3.0 Saved progress of intermediate image creation after upload.
* @since 5.5.0 Ensured that galleries can be output as a list of links in feeds.
* @since 5.6.0 Replaced order-style PHP type conversion functions with typecasts. Fix logic for
* an array of image dimensions.
*
* @param array $attr {
* Attributes of the gallery shortcode.
*
* @type string $order Order of the images in the gallery. Default 'ASC'. Accepts 'ASC', 'DESC'.
* @type string $orderby The field to use when ordering the images. Default 'menu_order ID'.
* Accepts any valid SQL ORDERBY statement.
* @type int $id Post ID.
* @type string $itemtag HTML tag to use for each image in the gallery.
* Default 'dl', or 'figure' when the theme registers HTML5 gallery support.
* @type string $icontag HTML tag to use for each image's icon.
* Default 'dt', or 'div' when the theme registers HTML5 gallery support.
* @type string $captiontag HTML tag to use for each image's caption.
* Default 'dd', or 'figcaption' when the theme registers HTML5 gallery support.
* @type int $columns Number of columns of images to display. Default 3.
* @type string|int[] $size Size of the images to display. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @type string $ids A comma-separated list of IDs of attachments to display. Default empty.
* @type string $include A comma-separated list of IDs of attachments to include. Default empty.
* @type string $exclude A comma-separated list of IDs of attachments to exclude. Default empty.
* @type string $link What to link each image to. Default empty (links to the attachment page).
* Accepts 'file', 'none'.
* }
* @return string HTML content to display gallery.
*/
function gallery_shortcode( $attr ) {
$post = get_post();
static $instance = 0;
++$instance;
if ( ! empty( $attr['ids'] ) ) {
// 'ids' is explicitly ordered, unless you specify otherwise.
if ( empty( $attr['orderby'] ) ) {
$attr['orderby'] = 'post__in';
}
$attr['include'] = $attr['ids'];
}
/**
* Filters the default gallery shortcode output.
*
* If the filtered output isn't empty, it will be used instead of generating
* the default gallery template.
*
* @since 2.5.0
* @since 4.2.0 The `$instance` parameter was added.
*
* @see gallery_shortcode()
*
* @param string $output The gallery output. Default empty.
* @param array $attr Attributes of the gallery shortcode.
* @param int $instance Unique numeric ID of this gallery shortcode instance.
*/
$output = apply_filters( 'post_gallery', '', $attr, $instance );
if ( ! empty( $output ) ) {
return $output;
}
$html5 = current_theme_supports( 'html5', 'gallery' );
$atts = shortcode_atts(
array(
'order' => 'ASC',
'orderby' => 'menu_order ID',
'id' => $post ? $post->ID : 0,
'itemtag' => $html5 ? 'figure' : 'dl',
'icontag' => $html5 ? 'div' : 'dt',
'captiontag' => $html5 ? 'figcaption' : 'dd',
'columns' => 3,
'size' => 'thumbnail',
'include' => '',
'exclude' => '',
'link' => '',
),
$attr,
'gallery'
);
$id = (int) $atts['id'];
if ( ! empty( $atts['include'] ) ) {
$_attachments = get_posts(
array(
'include' => $atts['include'],
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
'order' => $atts['order'],
'orderby' => $atts['orderby'],
)
);
$attachments = array();
foreach ( $_attachments as $key => $val ) {
$attachments[ $val->ID ] = $_attachments[ $key ];
}
} elseif ( ! empty( $atts['exclude'] ) ) {
$post_parent_id = $id;
$attachments = get_children(
array(
'post_parent' => $id,
'exclude' => $atts['exclude'],
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
'order' => $atts['order'],
'orderby' => $atts['orderby'],
)
);
} else {
$post_parent_id = $id;
$attachments = get_children(
array(
'post_parent' => $id,
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
'order' => $atts['order'],
'orderby' => $atts['orderby'],
)
);
}
if ( ! empty( $post_parent_id ) ) {
$post_parent = get_post( $post_parent_id );
// Terminate the shortcode execution if the user cannot read the post or it is password-protected.
if ( ! is_post_publicly_viewable( $post_parent->ID ) && ! current_user_can( 'read_post', $post_parent->ID )
|| post_password_required( $post_parent )
) {
return '';
}
}
if ( empty( $attachments ) ) {
return '';
}
if ( is_feed() ) {
$output = "\n";
foreach ( $attachments as $att_id => $attachment ) {
if ( ! empty( $atts['link'] ) ) {
if ( 'none' === $atts['link'] ) {
$output .= wp_get_attachment_image( $att_id, $atts['size'], false, $attr );
} else {
$output .= wp_get_attachment_link( $att_id, $atts['size'], false );
}
} else {
$output .= wp_get_attachment_link( $att_id, $atts['size'], true );
}
$output .= "\n";
}
return $output;
}
$itemtag = tag_escape( $atts['itemtag'] );
$captiontag = tag_escape( $atts['captiontag'] );
$icontag = tag_escape( $atts['icontag'] );
$valid_tags = wp_kses_allowed_html( 'post' );
if ( ! isset( $valid_tags[ $itemtag ] ) ) {
$itemtag = 'dl';
}
if ( ! isset( $valid_tags[ $captiontag ] ) ) {
$captiontag = 'dd';
}
if ( ! isset( $valid_tags[ $icontag ] ) ) {
$icontag = 'dt';
}
$columns = (int) $atts['columns'];
$itemwidth = $columns > 0 ? floor( 100 / $columns ) : 100;
$float = is_rtl() ? 'right' : 'left';
$selector = "gallery-{$instance}";
$gallery_style = '';
/**
* Filters whether to print default gallery styles.
*
* @since 3.1.0
*
* @param bool $print Whether to print default gallery styles.
* Defaults to false if the theme supports HTML5 galleries.
* Otherwise, defaults to true.
*/
if ( apply_filters( 'use_default_gallery_style', ! $html5 ) ) {
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
$gallery_style = "
<style{$type_attr}>
#{$selector} {
margin: auto;
}
#{$selector} .gallery-item {
float: {$float};
margin-top: 10px;
text-align: center;
width: {$itemwidth}%;
}
#{$selector} img {
border: 2px solid #cfcfcf;
}
#{$selector} .gallery-caption {
margin-left: 0;
}
/* see gallery_shortcode() in wp-includes/media.php */
</style>\n\t\t";
}
$size_class = sanitize_html_class( is_array( $atts['size'] ) ? implode( 'x', $atts['size'] ) : $atts['size'] );
$gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
/**
* Filters the default gallery shortcode CSS styles.
*
* @since 2.5.0
*
* @param string $gallery_style Default CSS styles and opening HTML div container
* for the gallery shortcode output.
*/
$output = apply_filters( 'gallery_style', $gallery_style . $gallery_div );
$i = 0;
foreach ( $attachments as $id => $attachment ) {
$attr = ( trim( $attachment->post_excerpt ) ) ? array( 'aria-describedby' => "$selector-$id" ) : '';
if ( ! empty( $atts['link'] ) && 'file' === $atts['link'] ) {
$image_output = wp_get_attachment_link( $id, $atts['size'], false, false, false, $attr );
} elseif ( ! empty( $atts['link'] ) && 'none' === $atts['link'] ) {
$image_output = wp_get_attachment_image( $id, $atts['size'], false, $attr );
} else {
$image_output = wp_get_attachment_link( $id, $atts['size'], true, false, false, $attr );
}
$image_meta = wp_get_attachment_metadata( $id );
$orientation = '';
if ( isset( $image_meta['height'], $image_meta['width'] ) ) {
$orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
}
$output .= "<{$itemtag} class='gallery-item'>";
$output .= "
<{$icontag} class='gallery-icon {$orientation}'>
$image_output
</{$icontag}>";
if ( $captiontag && trim( $attachment->post_excerpt ) ) {
$output .= "
<{$captiontag} class='wp-caption-text gallery-caption' id='$selector-$id'>
" . wptexturize( $attachment->post_excerpt ) . "
</{$captiontag}>";
}
$output .= "</{$itemtag}>";
if ( ! $html5 && $columns > 0 && 0 === ++$i % $columns ) {
$output .= '<br style="clear: both" />';
}
}
if ( ! $html5 && $columns > 0 && 0 !== $i % $columns ) {
$output .= "
<br style='clear: both' />";
}
$output .= "
</div>\n";
return $output;
}
/**
* Outputs the templates used by playlists.
*
* @since 3.9.0
*/
function wp_underscore_playlist_templates() {
?>
<script type="text/html" id="tmpl-wp-playlist-current-item">
<# if ( data.thumb && data.thumb.src ) { #>
<img src="{{ data.thumb.src }}" alt="" />
<# } #>
<div class="wp-playlist-caption">
<span class="wp-playlist-item-meta wp-playlist-item-title">
<# if ( data.meta.album || data.meta.artist ) { #>
<?php
/* translators: %s: Playlist item title. */
printf( _x( '“%s”', 'playlist item title' ), '{{ data.title }}' );
?>
<# } else { #>
{{ data.title }}
<# } #>
</span>
<# if ( data.meta.album ) { #><span class="wp-playlist-item-meta wp-playlist-item-album">{{ data.meta.album }}</span><# } #>
<# if ( data.meta.artist ) { #><span class="wp-playlist-item-meta wp-playlist-item-artist">{{ data.meta.artist }}</span><# } #>
</div>
</script>
<script type="text/html" id="tmpl-wp-playlist-item">
<div class="wp-playlist-item">
<a class="wp-playlist-caption" href="{{ data.src }}">
{{ data.index ? ( data.index + '. ' ) : '' }}
<# if ( data.caption ) { #>
{{ data.caption }}
<# } else { #>
<# if ( data.artists && data.meta.artist ) { #>
<span class="wp-playlist-item-title">
<?php
/* translators: %s: Playlist item title. */
printf( _x( '“%s”', 'playlist item title' ), '{{{ data.title }}}' );
?>
</span>
<span class="wp-playlist-item-artist"> — {{ data.meta.artist }}</span>
<# } else { #>
<span class="wp-playlist-item-title">{{{ data.title }}}</span>
<# } #>
<# } #>
</a>
<# if ( data.meta.length_formatted ) { #>
<div class="wp-playlist-item-length">{{ data.meta.length_formatted }}</div>
<# } #>
</div>
</script>
<?php
}
/**
* Outputs and enqueues default scripts and styles for playlists.
*
* @since 3.9.0
*
* @param string $type Type of playlist. Accepts 'audio' or 'video'.
*/
function wp_playlist_scripts( $type ) {
wp_enqueue_style( 'wp-mediaelement' );
wp_enqueue_script( 'wp-playlist' );
?>
<!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ); ?>');</script><![endif]-->
<?php
add_action( 'wp_footer', 'wp_underscore_playlist_templates', 0 );
add_action( 'admin_footer', 'wp_underscore_playlist_templates', 0 );
}
/**
* Builds the Playlist shortcode output.
*
* This implements the functionality of the playlist shortcode for displaying
* a collection of WordPress audio or video files in a post.
*
* @since 3.9.0
*
* @global int $content_width
*
* @param array $attr {
* Array of default playlist attributes.
*
* @type string $type Type of playlist to display. Accepts 'audio' or 'video'. Default 'audio'.
* @type string $order Designates ascending or descending order of items in the playlist.
* Accepts 'ASC', 'DESC'. Default 'ASC'.
* @type string $orderby Any column, or columns, to sort the playlist. If $ids are
* passed, this defaults to the order of the $ids array ('post__in').
* Otherwise default is 'menu_order ID'.
* @type int $id If an explicit $ids array is not present, this parameter
* will determine which attachments are used for the playlist.
* Default is the current post ID.
* @type array $ids Create a playlist out of these explicit attachment IDs. If empty,
* a playlist will be created from all $type attachments of $id.
* Default empty.
* @type array $exclude List of specific attachment IDs to exclude from the playlist. Default empty.
* @type string $style Playlist style to use. Accepts 'light' or 'dark'. Default 'light'.
* @type bool $tracklist Whether to show or hide the playlist. Default true.
* @type bool $tracknumbers Whether to show or hide the numbers next to entries in the playlist. Default true.
* @type bool $images Show or hide the video or audio thumbnail (Featured Image/post
* thumbnail). Default true.
* @type bool $artists Whether to show or hide artist name in the playlist. Default true.
* }
*
* @return string Playlist output. Empty string if the passed type is unsupported.
*/
function wp_playlist_shortcode( $attr ) {
global $content_width;
$post = get_post();
static $instance = 0;
++$instance;
if ( ! empty( $attr['ids'] ) ) {
// 'ids' is explicitly ordered, unless you specify otherwise.
if ( empty( $attr['orderby'] ) ) {
$attr['orderby'] = 'post__in';
}
$attr['include'] = $attr['ids'];
}
/**
* Filters the playlist output.
*
* Returning a non-empty value from the filter will short-circuit generation
* of the default playlist output, returning the passed value instead.
*
* @since 3.9.0
* @since 4.2.0 The `$instance` parameter was added.
*
* @param string $output Playlist output. Default empty.
* @param array $attr An array of shortcode attributes.
* @param int $instance Unique numeric ID of this playlist shortcode instance.
*/
$output = apply_filters( 'post_playlist', '', $attr, $instance );
if ( ! empty( $output ) ) {
return $output;
}
$atts = shortcode_atts(
array(
'type' => 'audio',
'order' => 'ASC',
'orderby' => 'menu_order ID',
'id' => $post ? $post->ID : 0,
'include' => '',
'exclude' => '',
'style' => 'light',
'tracklist' => true,
'tracknumbers' => true,
'images' => true,
'artists' => true,
),
$attr,
'playlist'
);
$id = (int) $atts['id'];
if ( 'audio' !== $atts['type'] ) {
$atts['type'] = 'video';
}
$args = array(
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => $atts['type'],
'order' => $atts['order'],
'orderby' => $atts['orderby'],
);
if ( ! empty( $atts['include'] ) ) {
$args['include'] = $atts['include'];
$_attachments = get_posts( $args );
$attachments = array();
foreach ( $_attachments as $key => $val ) {
$attachments[ $val->ID ] = $_attachments[ $key ];
}
} elseif ( ! empty( $atts['exclude'] ) ) {
$args['post_parent'] = $id;
$args['exclude'] = $atts['exclude'];
$attachments = get_children( $args );
} else {
$args['post_parent'] = $id;
$attachments = get_children( $args );
}
if ( ! empty( $args['post_parent'] ) ) {
$post_parent = get_post( $id );
// Terminate the shortcode execution if the user cannot read the post or it is password-protected.
if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) {
return '';
}
}
if ( empty( $attachments ) ) {
return '';
}
if ( is_feed() ) {
$output = "\n";
foreach ( $attachments as $att_id => $attachment ) {
$output .= wp_get_attachment_link( $att_id ) . "\n";
}
return $output;
}
$outer = 22; // Default padding and border of wrapper.
$default_width = 640;
$default_height = 360;
$theme_width = empty( $content_width ) ? $default_width : ( $content_width - $outer );
$theme_height = empty( $content_width ) ? $default_height : round( ( $default_height * $theme_width ) / $default_width );
$data = array(
'type' => $atts['type'],
// Don't pass strings to JSON, will be truthy in JS.
'tracklist' => wp_validate_boolean( $atts['tracklist'] ),
'tracknumbers' => wp_validate_boolean( $atts['tracknumbers'] ),
'images' => wp_validate_boolean( $atts['images'] ),
'artists' => wp_validate_boolean( $atts['artists'] ),
);
$tracks = array();
foreach ( $attachments as $attachment ) {
$url = wp_get_attachment_url( $attachment->ID );
$ftype = wp_check_filetype( $url, wp_get_mime_types() );
$track = array(
'src' => $url,
'type' => $ftype['type'],
'title' => $attachment->post_title,
'caption' => $attachment->post_excerpt,
'description' => $attachment->post_content,
);
$track['meta'] = array();
$meta = wp_get_attachment_metadata( $attachment->ID );
if ( ! empty( $meta ) ) {
foreach ( wp_get_attachment_id3_keys( $attachment ) as $key => $label ) {
if ( ! empty( $meta[ $key ] ) ) {
$track['meta'][ $key ] = $meta[ $key ];
}
}
if ( 'video' === $atts['type'] ) {
if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
$width = $meta['width'];
$height = $meta['height'];
$theme_height = round( ( $height * $theme_width ) / $width );
} else {
$width = $default_width;
$height = $default_height;
}
$track['dimensions'] = array(
'original' => compact( 'width', 'height' ),
'resized' => array(
'width' => $theme_width,
'height' => $theme_height,
),
);
}
}
if ( $atts['images'] ) {
$thumb_id = get_post_thumbnail_id( $attachment->ID );
if ( ! empty( $thumb_id ) ) {
list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'full' );
$track['image'] = compact( 'src', 'width', 'height' );
list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' );
$track['thumb'] = compact( 'src', 'width', 'height' );
} else {
$src = wp_mime_type_icon( $attachment->ID, '.svg' );
$width = 48;
$height = 64;
$track['image'] = compact( 'src', 'width', 'height' );
$track['thumb'] = compact( 'src', 'width', 'height' );
}
}
$tracks[] = $track;
}
$data['tracks'] = $tracks;
$safe_type = esc_attr( $atts['type'] );
$safe_style = esc_attr( $atts['style'] );
ob_start();
if ( 1 === $instance ) {
/**
* Prints and enqueues playlist scripts, styles, and JavaScript templates.
*
* @since 3.9.0
*
* @param string $type Type of playlist. Possible values are 'audio' or 'video'.
* @param string $style The 'theme' for the playlist. Core provides 'light' and 'dark'.
*/
do_action( 'wp_playlist_scripts', $atts['type'], $atts['style'] );
}
?>
<div class="wp-playlist wp-<?php echo $safe_type; ?>-playlist wp-playlist-<?php echo $safe_style; ?>">
<?php if ( 'audio' === $atts['type'] ) : ?>
<div class="wp-playlist-current-item"></div>
<?php endif; ?>
<<?php echo $safe_type; ?> controls="controls" preload="none" width="<?php echo (int) $theme_width; ?>"
<?php
if ( 'video' === $safe_type ) {
echo ' height="', (int) $theme_height, '"';
}
?>
></<?php echo $safe_type; ?>>
<div class="wp-playlist-next"></div>
<div class="wp-playlist-prev"></div>
<noscript>
<ol>
<?php
foreach ( $attachments as $att_id => $attachment ) {
printf( '<li>%s</li>', wp_get_attachment_link( $att_id ) );
}
?>
</ol>
</noscript>
<script type="application/json" class="wp-playlist-script"><?php echo wp_json_encode( $data ); ?></script>
</div>
<?php
return ob_get_clean();
}
add_shortcode( 'playlist', 'wp_playlist_shortcode' );
/**
* Provides a No-JS Flash fallback as a last resort for audio / video.
*
* @since 3.6.0
*
* @param string $url The media element URL.
* @return string Fallback HTML.
*/
function wp_mediaelement_fallback( $url ) {
/**
* Filters the MediaElement fallback output for no-JS.
*
* @since 3.6.0
*
* @param string $output Fallback output for no-JS.
* @param string $url Media file URL.
*/
return apply_filters( 'wp_mediaelement_fallback', sprintf( '<a href="%1$s">%1$s</a>', esc_url( $url ) ), $url );
}
/**
* Returns a filtered list of supported audio formats.
*
* @since 3.6.0
*
* @return string[] Supported audio formats.
*/
function wp_get_audio_extensions() {
/**
* Filters the list of supported audio formats.
*
* @since 3.6.0
*
* @param string[] $extensions An array of supported audio formats. Defaults are
* 'mp3', 'ogg', 'flac', 'm4a', 'wav'.
*/
return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'flac', 'm4a', 'wav' ) );
}
/**
* Returns useful keys to use to lookup data from an attachment's stored metadata.
*
* @since 3.9.0
*
* @param WP_Post $attachment The current attachment, provided for context.
* @param string $context Optional. The context. Accepts 'edit', 'display'. Default 'display'.
* @return string[] Key/value pairs of field keys to labels.
*/
function wp_get_attachment_id3_keys( $attachment, $context = 'display' ) {
$fields = array(
'artist' => __( 'Artist' ),
'album' => __( 'Album' ),
);
if ( 'display' === $context ) {
$fields['genre'] = __( 'Genre' );
$fields['year'] = __( 'Year' );
$fields['length_formatted'] = _x( 'Length', 'video or audio' );
} elseif ( 'js' === $context ) {
$fields['bitrate'] = __( 'Bitrate' );
$fields['bitrate_mode'] = __( 'Bitrate Mode' );
}
/**
* Filters the editable list of keys to look up data from an attachment's metadata.
*
* @since 3.9.0
*
* @param array $fields Key/value pairs of field keys to labels.
* @param WP_Post $attachment Attachment object.
* @param string $context The context. Accepts 'edit', 'display'. Default 'display'.
*/
return apply_filters( 'wp_get_attachment_id3_keys', $fields, $attachment, $context );
}
/**
* Builds the Audio shortcode output.
*
* This implements the functionality of the Audio Shortcode for displaying
* WordPress mp3s in a post.
*
* @since 3.6.0
* @since 6.8.0 Added the 'muted' attribute.
*
* @param array $attr {
* Attributes of the audio shortcode.
*
* @type string $src URL to the source of the audio file. Default empty.
* @type string $loop The 'loop' attribute for the `<audio>` element. Default empty.
* @type string $autoplay The 'autoplay' attribute for the `<audio>` element. Default empty.
* @type string $muted The 'muted' attribute for the `<audio>` element. Default 'false'.
* @type string $preload The 'preload' attribute for the `<audio>` element. Default 'none'.
* @type string $class The 'class' attribute for the `<audio>` element. Default 'wp-audio-shortcode'.
* @type string $style The 'style' attribute for the `<audio>` element. Default 'width: 100%;'.
* }
* @param string $content Shortcode content.
* @return string|void HTML content to display audio.
*/
function wp_audio_shortcode( $attr, $content = '' ) {
$post_id = get_post() ? get_the_ID() : 0;
static $instance = 0;
++$instance;
/**
* Filters the default audio shortcode output.
*
* If the filtered output isn't empty, it will be used instead of generating the default audio template.
*
* @since 3.6.0
*
* @param string $html Empty variable to be replaced with shortcode markup.
* @param array $attr Attributes of the shortcode. See {@see wp_audio_shortcode()}.
* @param string $content Shortcode content.
* @param int $instance Unique numeric ID of this audio shortcode instance.
*/
$override = apply_filters( 'wp_audio_shortcode_override', '', $attr, $content, $instance );
if ( '' !== $override ) {
return $override;
}
$audio = null;
$default_types = wp_get_audio_extensions();
$defaults_atts = array(
'src' => '',
'loop' => '',
'autoplay' => '',
'muted' => 'false',
'preload' => 'none',
'class' => 'wp-audio-shortcode',
'style' => 'width: 100%;',
);
foreach ( $default_types as $type ) {
$defaults_atts[ $type ] = '';
}
$atts = shortcode_atts( $defaults_atts, $attr, 'audio' );
$primary = false;
if ( ! empty( $atts['src'] ) ) {
$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );
if ( ! in_array( strtolower( $type['ext'] ), $default_types, true ) ) {
return sprintf( '<a class="wp-embedded-audio" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
}
$primary = true;
array_unshift( $default_types, 'src' );
} else {
foreach ( $default_types as $ext ) {
if ( ! empty( $atts[ $ext ] ) ) {
$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
if ( strtolower( $type['ext'] ) === $ext ) {
$primary = true;
}
}
}
}
if ( ! $primary ) {
$audios = get_attached_media( 'audio', $post_id );
if ( empty( $audios ) ) {
return;
}
$audio = reset( $audios );
$atts['src'] = wp_get_attachment_url( $audio->ID );
if ( empty( $atts['src'] ) ) {
return;
}
array_unshift( $default_types, 'src' );
}
/**
* Filters the media library used for the audio shortcode.
*
* @since 3.6.0
*
* @param string $library Media library used for the audio shortcode.
*/
$library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
if ( 'mediaelement' === $library && did_action( 'init' ) ) {
wp_enqueue_style( 'wp-mediaelement' );
wp_enqueue_script( 'wp-mediaelement' );
}
/**
* Filters the class attribute for the audio shortcode output container.
*
* @since 3.6.0
* @since 4.9.0 The `$atts` parameter was added.
*
* @param string $class CSS class or list of space-separated classes.
* @param array $atts Array of audio shortcode attributes.
*/
$atts['class'] = apply_filters( 'wp_audio_shortcode_class', $atts['class'], $atts );
$html_atts = array(
'class' => $atts['class'],
'id' => sprintf( 'audio-%d-%d', $post_id, $instance ),
'loop' => wp_validate_boolean( $atts['loop'] ),
'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
'muted' => wp_validate_boolean( $atts['muted'] ),
'preload' => $atts['preload'],
'style' => $atts['style'],
);
// These ones should just be omitted altogether if they are blank.
foreach ( array( 'loop', 'autoplay', 'preload', 'muted' ) as $a ) {
if ( empty( $html_atts[ $a ] ) ) {
unset( $html_atts[ $a ] );
}
}
$attr_strings = array();
foreach ( $html_atts as $attribute_name => $attribute_value ) {
if ( in_array( $attribute_name, array( 'loop', 'autoplay', 'muted' ), true ) && true === $attribute_value ) {
// Add boolean attributes without a value.
$attr_strings[] = esc_attr( $attribute_name );
} elseif ( 'preload' === $attribute_name && ! empty( $attribute_value ) ) {
// Handle the preload attribute with specific allowed values.
$allowed_preload_values = array( 'none', 'metadata', 'auto' );
if ( in_array( $attribute_value, $allowed_preload_values, true ) ) {
$attr_strings[] = sprintf( '%s="%s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
}
} else {
// For other attributes, include the value.
$attr_strings[] = sprintf( '%s="%s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
}
}
$html = '';
if ( 'mediaelement' === $library && 1 === $instance ) {
$html .= "<!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->\n";
}
$html .= sprintf( '<audio %s controls="controls">', implode( ' ', $attr_strings ) );
$fileurl = '';
$source = '<source type="%s" src="%s" />';
foreach ( $default_types as $fallback ) {
if ( ! empty( $atts[ $fallback ] ) ) {
if ( empty( $fileurl ) ) {
$fileurl = $atts[ $fallback ];
}
$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
$url = add_query_arg( '_', $instance, $atts[ $fallback ] );
$html .= sprintf( $source, $type['type'], esc_url( $url ) );
}
}
if ( 'mediaelement' === $library ) {
$html .= wp_mediaelement_fallback( $fileurl );
}
$html .= '</audio>';
/**
* Filters the audio shortcode output.
*
* @since 3.6.0
*
* @param string $html Audio shortcode HTML output.
* @param array $atts Array of audio shortcode attributes.
* @param string $audio Audio file.
* @param int $post_id Post ID.
* @param string $library Media library used for the audio shortcode.
*/
return apply_filters( 'wp_audio_shortcode', $html, $atts, $audio, $post_id, $library );
}
add_shortcode( 'audio', 'wp_audio_shortcode' );
/**
* Returns a filtered list of supported video formats.
*
* @since 3.6.0
*
* @return string[] List of supported video formats.
*/
function wp_get_video_extensions() {
/**
* Filters the list of supported video formats.
*
* @since 3.6.0
*
* @param string[] $extensions An array of supported video formats. Defaults are
* 'mp4', 'm4v', 'webm', 'ogv', 'flv'.
*/
return apply_filters( 'wp_video_extensions', array( 'mp4', 'm4v', 'webm', 'ogv', 'flv' ) );
}
/**
* Builds the Video shortcode output.
*
* This implements the functionality of the Video Shortcode for displaying
* WordPress mp4s in a post.
*
* @since 3.6.0
*
* @global int $content_width
*
* @param array $attr {
* Attributes of the shortcode.
*
* @type string $src URL to the source of the video file. Default empty.
* @type int $height Height of the video embed in pixels. Default 360.
* @type int $width Width of the video embed in pixels. Default $content_width or 640.
* @type string $poster The 'poster' attribute for the `<video>` element. Default empty.
* @type string $loop The 'loop' attribute for the `<video>` element. Default empty.
* @type string $autoplay The 'autoplay' attribute for the `<video>` element. Default empty.
* @type string $muted The 'muted' attribute for the `<video>` element. Default false.
* @type string $preload The 'preload' attribute for the `<video>` element.
* Default 'metadata'.
* @type string $class The 'class' attribute for the `<video>` element.
* Default 'wp-video-shortcode'.
* }
* @param string $content Shortcode content.
* @return string|void HTML content to display video.
*/
function wp_video_shortcode( $attr, $content = '' ) {
global $content_width;
$post_id = get_post() ? get_the_ID() : 0;
static $instance = 0;
++$instance;
/**
* Filters the default video shortcode output.
*
* If the filtered output isn't empty, it will be used instead of generating
* the default video template.
*
* @since 3.6.0
*
* @see wp_video_shortcode()
*
* @param string $html Empty variable to be replaced with shortcode markup.
* @param array $attr Attributes of the shortcode. See {@see wp_video_shortcode()}.
* @param string $content Video shortcode content.
* @param int $instance Unique numeric ID of this video shortcode instance.
*/
$override = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instance );
if ( '' !== $override ) {
return $override;
}
$video = null;
$default_types = wp_get_video_extensions();
$defaults_atts = array(
'src' => '',
'poster' => '',
'loop' => '',
'autoplay' => '',
'muted' => 'false',
'preload' => 'metadata',
'width' => 640,
'height' => 360,
'class' => 'wp-video-shortcode',
);
foreach ( $default_types as $type ) {
$defaults_atts[ $type ] = '';
}
$atts = shortcode_atts( $defaults_atts, $attr, 'video' );
if ( is_admin() ) {
// Shrink the video so it isn't huge in the admin.
if ( $atts['width'] > $defaults_atts['width'] ) {
$atts['height'] = round( ( $atts['height'] * $defaults_atts['width'] ) / $atts['width'] );
$atts['width'] = $defaults_atts['width'];
}
} else {
// If the video is bigger than the theme.
if ( ! empty( $content_width ) && $atts['width'] > $content_width ) {
$atts['height'] = round( ( $atts['height'] * $content_width ) / $atts['width'] );
$atts['width'] = $content_width;
}
}
$is_vimeo = false;
$is_youtube = false;
$yt_pattern = '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#';
$vimeo_pattern = '#^https?://(.+\.)?vimeo\.com/.*#';
$primary = false;
if ( ! empty( $atts['src'] ) ) {
$is_vimeo = ( preg_match( $vimeo_pattern, $atts['src'] ) );
$is_youtube = ( preg_match( $yt_pattern, $atts['src'] ) );
if ( ! $is_youtube && ! $is_vimeo ) {
$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );
if ( ! in_array( strtolower( $type['ext'] ), $default_types, true ) ) {
return sprintf( '<a class="wp-embedded-video" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
}
}
if ( $is_vimeo ) {
wp_enqueue_script( 'mediaelement-vimeo' );
}
$primary = true;
array_unshift( $default_types, 'src' );
} else {
foreach ( $default_types as $ext ) {
if ( ! empty( $atts[ $ext ] ) ) {
$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
if ( strtolower( $type['ext'] ) === $ext ) {
$primary = true;
}
}
}
}
if ( ! $primary ) {
$videos = get_attached_media( 'video', $post_id );
if ( empty( $videos ) ) {
return;
}
$video = reset( $videos );
$atts['src'] = wp_get_attachment_url( $video->ID );
if ( empty( $atts['src'] ) ) {
return;
}
array_unshift( $default_types, 'src' );
}
/**
* Filters the media library used for the video shortcode.
*
* @since 3.6.0
*
* @param string $library Media library used for the video shortcode.
*/
$library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
if ( 'mediaelement' === $library && did_action( 'init' ) ) {
wp_enqueue_style( 'wp-mediaelement' );
wp_enqueue_script( 'wp-mediaelement' );
wp_enqueue_script( 'mediaelement-vimeo' );
}
/*
* MediaElement.js has issues with some URL formats for Vimeo and YouTube,
* so update the URL to prevent the ME.js player from breaking.
*/
if ( 'mediaelement' === $library ) {
if ( $is_youtube ) {
// Remove `feature` query arg and force SSL - see #40866.
$atts['src'] = remove_query_arg( 'feature', $atts['src'] );
$atts['src'] = set_url_scheme( $atts['src'], 'https' );
} elseif ( $is_vimeo ) {
// Remove all query arguments and force SSL - see #40866.
$parsed_vimeo_url = wp_parse_url( $atts['src'] );
$vimeo_src = 'https://' . $parsed_vimeo_url['host'] . $parsed_vimeo_url['path'];
// Add loop param for mejs bug - see #40977, not needed after #39686.
$loop = $atts['loop'] ? '1' : '0';
$atts['src'] = add_query_arg( 'loop', $loop, $vimeo_src );
}
}
/**
* Filters the class attribute for the video shortcode output container.
*
* @since 3.6.0
* @since 4.9.0 The `$atts` parameter was added.
*
* @param string $class CSS class or list of space-separated classes.
* @param array $atts Array of video shortcode attributes.
*/
$atts['class'] = apply_filters( 'wp_video_shortcode_class', $atts['class'], $atts );
$html_atts = array(
'class' => $atts['class'],
'id' => sprintf( 'video-%d-%d', $post_id, $instance ),
'width' => absint( $atts['width'] ),
'height' => absint( $atts['height'] ),
'poster' => esc_url( $atts['poster'] ),
'loop' => wp_validate_boolean( $atts['loop'] ),
'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
'muted' => wp_validate_boolean( $atts['muted'] ),
'preload' => $atts['preload'],
);
// These ones should just be omitted altogether if they are blank.
foreach ( array( 'poster', 'loop', 'autoplay', 'preload', 'muted' ) as $a ) {
if ( empty( $html_atts[ $a ] ) ) {
unset( $html_atts[ $a ] );
}
}
$attr_strings = array();
foreach ( $html_atts as $attribute_name => $attribute_value ) {
if ( in_array( $attribute_name, array( 'loop', 'autoplay', 'muted' ), true ) && true === $attribute_value ) {
// Add boolean attributes without their value for true.
$attr_strings[] = esc_attr( $attribute_name );
} elseif ( 'preload' === $attribute_name && ! empty( $attribute_value ) ) {
// Handle the preload attribute with specific allowed values.
$allowed_preload_values = array( 'none', 'metadata', 'auto' );
if ( in_array( $attribute_value, $allowed_preload_values, true ) ) {
$attr_strings[] = sprintf( '%s="%s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
}
} elseif ( ! empty( $attribute_value ) ) {
// For non-boolean attributes, add them with their value.
$attr_strings[] = sprintf( '%s="%s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
}
}
$html = '';
if ( 'mediaelement' === $library && 1 === $instance ) {
$html .= "<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->\n";
}
$html .= sprintf( '<video %s controls="controls">', implode( ' ', $attr_strings ) );
$fileurl = '';
$source = '<source type="%s" src="%s" />';
foreach ( $default_types as $fallback ) {
if ( ! empty( $atts[ $fallback ] ) ) {
if ( empty( $fileurl ) ) {
$fileurl = $atts[ $fallback ];
}
if ( 'src' === $fallback && $is_youtube ) {
$type = array( 'type' => 'video/youtube' );
} elseif ( 'src' === $fallback && $is_vimeo ) {
$type = array( 'type' => 'video/vimeo' );
} else {
$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
}
$url = add_query_arg( '_', $instance, $atts[ $fallback ] );
$html .= sprintf( $source, $type['type'], esc_url( $url ) );
}
}
if ( ! empty( $content ) ) {
if ( str_contains( $content, "\n" ) ) {
$content = str_replace( array( "\r\n", "\n", "\t" ), '', $content );
}
$html .= trim( $content );
}
if ( 'mediaelement' === $library ) {
$html .= wp_mediaelement_fallback( $fileurl );
}
$html .= '</video>';
$width_rule = '';
if ( ! empty( $atts['width'] ) ) {
$width_rule = sprintf( 'width: %dpx;', $atts['width'] );
}
$output = sprintf( '<div style="%s" class="wp-video">%s</div>', $width_rule, $html );
/**
* Filters the output of the video shortcode.
*
* @since 3.6.0
*
* @param string $output Video shortcode HTML output.
* @param array $atts Array of video shortcode attributes.
* @param string $video Video file.
* @param int $post_id Post ID.
* @param string $library Media library used for the video shortcode.
*/
return apply_filters( 'wp_video_shortcode', $output, $atts, $video, $post_id, $library );
}
add_shortcode( 'video', 'wp_video_shortcode' );
/**
* Gets the previous image link that has the same post parent.
*
* @since 5.8.0
*
* @see get_adjacent_image_link()
*
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param string|false $text Optional. Link text. Default false.
* @return string Markup for previous image link.
*/
function get_previous_image_link( $size = 'thumbnail', $text = false ) {
return get_adjacent_image_link( true, $size, $text );
}
/**
* Displays previous image link that has the same post parent.
*
* @since 2.5.0
*
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param string|false $text Optional. Link text. Default false.
*/
function previous_image_link( $size = 'thumbnail', $text = false ) {
echo get_previous_image_link( $size, $text );
}
/**
* Gets the next image link that has the same post parent.
*
* @since 5.8.0
*
* @see get_adjacent_image_link()
*
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param string|false $text Optional. Link text. Default false.
* @return string Markup for next image link.
*/
function get_next_image_link( $size = 'thumbnail', $text = false ) {
return get_adjacent_image_link( false, $size, $text );
}
/**
* Displays next image link that has the same post parent.
*
* @since 2.5.0
*
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param string|false $text Optional. Link text. Default false.
*/
function next_image_link( $size = 'thumbnail', $text = false ) {
echo get_next_image_link( $size, $text );
}
/**
* Gets the next or previous image link that has the same post parent.
*
* Retrieves the current attachment object from the $post global.
*
* @since 5.8.0
*
* @param bool $prev Optional. Whether to display the next (false) or previous (true) link. Default true.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $text Optional. Link text. Default false.
* @return string Markup for image link.
*/
function get_adjacent_image_link( $prev = true, $size = 'thumbnail', $text = false ) {
$post = get_post();
$attachments = array_values(
get_children(
array(
'post_parent' => $post->post_parent,
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
'order' => 'ASC',
'orderby' => 'menu_order ID',
)
)
);
foreach ( $attachments as $k => $attachment ) {
if ( (int) $attachment->ID === (int) $post->ID ) {
break;
}
}
$output = '';
$attachment_id = 0;
if ( $attachments ) {
$k = $prev ? $k - 1 : $k + 1;
if ( isset( $attachments[ $k ] ) ) {
$attachment_id = $attachments[ $k ]->ID;
$attr = array( 'alt' => get_the_title( $attachment_id ) );
$output = wp_get_attachment_link( $attachment_id, $size, true, false, $text, $attr );
}
}
$adjacent = $prev ? 'previous' : 'next';
/**
* Filters the adjacent image link.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type of adjacency,
* either 'next', or 'previous'.
*
* Possible hook names include:
*
* - `next_image_link`
* - `previous_image_link`
*
* @since 3.5.0
*
* @param string $output Adjacent image HTML markup.
* @param int $attachment_id Attachment ID
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param string $text Link text.
*/
return apply_filters( "{$adjacent}_image_link", $output, $attachment_id, $size, $text );
}
/**
* Displays next or previous image link that has the same post parent.
*
* Retrieves the current attachment object from the $post global.
*
* @since 2.5.0
*
* @param bool $prev Optional. Whether to display the next (false) or previous (true) link. Default true.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $text Optional. Link text. Default false.
*/
function adjacent_image_link( $prev = true, $size = 'thumbnail', $text = false ) {
echo get_adjacent_image_link( $prev, $size, $text );
}
/**
* Retrieves taxonomies attached to given the attachment.
*
* @since 2.5.0
* @since 4.7.0 Introduced the `$output` parameter.
*
* @param int|array|object $attachment Attachment ID, data array, or data object.
* @param string $output Output type. 'names' to return an array of taxonomy names,
* or 'objects' to return an array of taxonomy objects.
* Default is 'names'.
* @return string[]|WP_Taxonomy[] List of taxonomies or taxonomy names. Empty array on failure.
*/
function get_attachment_taxonomies( $attachment, $output = 'names' ) {
if ( is_int( $attachment ) ) {
$attachment = get_post( $attachment );
} elseif ( is_array( $attachment ) ) {
$attachment = (object) $attachment;
}
if ( ! is_object( $attachment ) ) {
return array();
}
$file = get_attached_file( $attachment->ID );
$filename = wp_basename( $file );
$objects = array( 'attachment' );
if ( str_contains( $filename, '.' ) ) {
$objects[] = 'attachment:' . substr( $filename, strrpos( $filename, '.' ) + 1 );
}
if ( ! empty( $attachment->post_mime_type ) ) {
$objects[] = 'attachment:' . $attachment->post_mime_type;
if ( str_contains( $attachment->post_mime_type, '/' ) ) {
foreach ( explode( '/', $attachment->post_mime_type ) as $token ) {
if ( ! empty( $token ) ) {
$objects[] = "attachment:$token";
}
}
}
}
$taxonomies = array();
foreach ( $objects as $object ) {
$taxes = get_object_taxonomies( $object, $output );
if ( $taxes ) {
$taxonomies = array_merge( $taxonomies, $taxes );
}
}
if ( 'names' === $output ) {
$taxonomies = array_unique( $taxonomies );
}
return $taxonomies;
}
/**
* Retrieves all of the taxonomies that are registered for attachments.
*
* Handles mime-type-specific taxonomies such as attachment:image and attachment:video.
*
* @since 3.5.0
*
* @see get_taxonomies()
*
* @param string $output Optional. The type of taxonomy output to return. Accepts 'names' or 'objects'.
* Default 'names'.
* @return string[]|WP_Taxonomy[] Array of names or objects of registered taxonomies for attachments.
*/
function get_taxonomies_for_attachments( $output = 'names' ) {
$taxonomies = array();
foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) {
foreach ( $taxonomy->object_type as $object_type ) {
if ( 'attachment' === $object_type || str_starts_with( $object_type, 'attachment:' ) ) {
if ( 'names' === $output ) {
$taxonomies[] = $taxonomy->name;
} else {
$taxonomies[ $taxonomy->name ] = $taxonomy;
}
break;
}
}
}
return $taxonomies;
}
/**
* Determines whether the value is an acceptable type for GD image functions.
*
* In PHP 8.0, the GD extension uses GdImage objects for its data structures.
* This function checks if the passed value is either a GdImage object instance
* or a resource of type `gd`. Any other type will return false.
*
* @since 5.6.0
*
* @param resource|GdImage|false $image A value to check the type for.
* @return bool True if `$image` is either a GD image resource or a GdImage instance,
* false otherwise.
*/
function is_gd_image( $image ) {
if ( $image instanceof GdImage
|| is_resource( $image ) && 'gd' === get_resource_type( $image )
) {
return true;
}
return false;
}
/**
* Creates a new GD image resource with transparency support.
*
* @todo Deprecate if possible.
*
* @since 2.9.0
*
* @param int $width Image width in pixels.
* @param int $height Image height in pixels.
* @return resource|GdImage|false The GD image resource or GdImage instance on success.
* False on failure.
*/
function wp_imagecreatetruecolor( $width, $height ) {
$img = imagecreatetruecolor( $width, $height );
if ( is_gd_image( $img )
&& function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' )
) {
imagealphablending( $img, false );
imagesavealpha( $img, true );
}
return $img;
}
/**
* Based on a supplied width/height example, returns the biggest possible dimensions based on the max width/height.
*
* @since 2.9.0
*
* @see wp_constrain_dimensions()
*
* @param int $example_width The width of an example embed.
* @param int $example_height The height of an example embed.
* @param int $max_width The maximum allowed width.
* @param int $max_height The maximum allowed height.
* @return int[] {
* An array of maximum width and height values.
*
* @type int $0 The maximum width in pixels.
* @type int $1 The maximum height in pixels.
* }
*/
function wp_expand_dimensions( $example_width, $example_height, $max_width, $max_height ) {
$example_width = (int) $example_width;
$example_height = (int) $example_height;
$max_width = (int) $max_width;
$max_height = (int) $max_height;
return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height );
}
/**
* Determines the maximum upload size allowed in php.ini.
*
* @since 2.5.0
*
* @return int Allowed upload size.
*/
function wp_max_upload_size() {
$u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
$p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) );
/**
* Filters the maximum upload size allowed in php.ini.
*
* @since 2.5.0
*
* @param int $size Max upload size limit in bytes.
* @param int $u_bytes Maximum upload filesize in bytes.
* @param int $p_bytes Maximum size of POST data in bytes.
*/
return apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
}
/**
* Returns a WP_Image_Editor instance and loads file into it.
*
* @since 3.5.0
*
* @param string $path Path to the file to load.
* @param array $args Optional. Additional arguments for retrieving the image editor.
* Default empty array.
* @return WP_Image_Editor|WP_Error The WP_Image_Editor object on success,
* a WP_Error object otherwise.
*/
function wp_get_image_editor( $path, $args = array() ) {
$args['path'] = $path;
// If the mime type is not set in args, try to extract and set it from the file.
if ( ! isset( $args['mime_type'] ) ) {
$file_info = wp_check_filetype( $args['path'] );
/*
* If $file_info['type'] is false, then we let the editor attempt to
* figure out the file type, rather than forcing a failure based on extension.
*/
if ( isset( $file_info ) && $file_info['type'] ) {
$args['mime_type'] = $file_info['type'];
}
}
// Check and set the output mime type mapped to the input type.
if ( isset( $args['mime_type'] ) ) {
$output_format = wp_get_image_editor_output_format( $path, $args['mime_type'] );
if ( isset( $output_format[ $args['mime_type'] ] ) ) {
$args['output_mime_type'] = $output_format[ $args['mime_type'] ];
}
}
$implementation = _wp_image_editor_choose( $args );
if ( $implementation ) {
$editor = new $implementation( $path );
$loaded = $editor->load();
if ( is_wp_error( $loaded ) ) {
return $loaded;
}
return $editor;
}
return new WP_Error( 'image_no_editor', __( 'No editor could be selected.' ) );
}
/**
* Tests whether there is an editor that supports a given mime type or methods.
*
* @since 3.5.0
*
* @param string|array $args Optional. Array of arguments to retrieve the image editor supports.
* Default empty array.
* @return bool True if an eligible editor is found; false otherwise.
*/
function wp_image_editor_supports( $args = array() ) {
return (bool) _wp_image_editor_choose( $args );
}
/**
* Tests which editors are capable of supporting the request.
*
* @ignore
* @since 3.5.0
*
* @param array $args Optional. Array of arguments for choosing a capable editor. Default empty array.
* @return string|false Class name for the first editor that claims to support the request.
* False if no editor claims to support the request.
*/
function _wp_image_editor_choose( $args = array() ) {
require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
require_once ABSPATH . WPINC . '/class-avif-info.php';
/**
* Filters the list of image editing library classes.
*
* @since 3.5.0
*
* @param string[] $image_editors Array of available image editor class names. Defaults are
* 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'.
*/
$implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) );
$editors = wp_cache_get( 'wp_image_editor_choose', 'image_editor' );
if ( ! is_array( $editors ) ) {
$editors = array();
}
// Cache the chosen editor implementation based on specific args and available implementations.
$cache_key = md5( serialize( array( $args, $implementations ) ) );
if ( isset( $editors[ $cache_key ] ) ) {
return $editors[ $cache_key ];
}
// Assume no support until a capable implementation is identified.
$editor = false;
foreach ( $implementations as $implementation ) {
if ( ! call_user_func( array( $implementation, 'test' ), $args ) ) {
continue;
}
// Implementation should support the passed mime type.
if ( isset( $args['mime_type'] ) &&
! call_user_func(
array( $implementation, 'supports_mime_type' ),
$args['mime_type']
) ) {
continue;
}
// Implementation should support requested methods.
if ( isset( $args['methods'] ) &&
array_diff( $args['methods'], get_class_methods( $implementation ) ) ) {
continue;
}
// Implementation should ideally support the output mime type as well if set and different than the passed type.
if (
isset( $args['mime_type'] ) &&
isset( $args['output_mime_type'] ) &&
$args['mime_type'] !== $args['output_mime_type'] &&
! call_user_func( array( $implementation, 'supports_mime_type' ), $args['output_mime_type'] )
) {
/*
* This implementation supports the input type but not the output type.
* Keep looking to see if we can find an implementation that supports both.
*/
$editor = $implementation;
continue;
}
// Favor the implementation that supports both input and output mime types.
$editor = $implementation;
break;
}
$editors[ $cache_key ] = $editor;
wp_cache_set( 'wp_image_editor_choose', $editors, 'image_editor', DAY_IN_SECONDS );
return $editor;
}
/**
* Prints default Plupload arguments.
*
* @since 3.4.0
*/
function wp_plupload_default_settings() {
$wp_scripts = wp_scripts();
$data = $wp_scripts->get_data( 'wp-plupload', 'data' );
if ( $data && str_contains( $data, '_wpPluploadSettings' ) ) {
return;
}
$max_upload_size = wp_max_upload_size();
$allowed_extensions = array_keys( get_allowed_mime_types() );
$extensions = array();
foreach ( $allowed_extensions as $extension ) {
$extensions = array_merge( $extensions, explode( '|', $extension ) );
}
/*
* Since 4.9 the `runtimes` setting is hardcoded in our version of Plupload to `html5,html4`,
* and the `flash_swf_url` and `silverlight_xap_url` are not used.
*/
$defaults = array(
'file_data_name' => 'async-upload', // Key passed to $_FILE.
'url' => admin_url( 'async-upload.php', 'relative' ),
'filters' => array(
'max_file_size' => $max_upload_size . 'b',
'mime_types' => array( array( 'extensions' => implode( ',', $extensions ) ) ),
),
);
/*
* Currently only iOS Safari supports multiple files uploading,
* but iOS 7.x has a bug that prevents uploading of videos when enabled.
* See #29602.
*/
if ( wp_is_mobile()
&& str_contains( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' )
&& str_contains( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' )
) {
$defaults['multi_selection'] = false;
}
// Check if WebP images can be edited.
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) {
$defaults['webp_upload_error'] = true;
}
// Check if AVIF images can be edited.
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
$defaults['avif_upload_error'] = true;
}
// Check if HEIC images can be edited.
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/heic' ) ) ) {
$defaults['heic_upload_error'] = true;
}
/**
* Filters the Plupload default settings.
*
* @since 3.4.0
*
* @param array $defaults Default Plupload settings array.
*/
$defaults = apply_filters( 'plupload_default_settings', $defaults );
$params = array(
'action' => 'upload-attachment',
);
/**
* Filters the Plupload default parameters.
*
* @since 3.4.0
*
* @param array $params Default Plupload parameters array.
*/
$params = apply_filters( 'plupload_default_params', $params );
$params['_wpnonce'] = wp_create_nonce( 'media-form' );
$defaults['multipart_params'] = $params;
$settings = array(
'defaults' => $defaults,
'browser' => array(
'mobile' => wp_is_mobile(),
'supported' => _device_can_upload(),
),
'limitExceeded' => is_multisite() && ! is_upload_space_available(),
);
$script = 'var _wpPluploadSettings = ' . wp_json_encode( $settings ) . ';';
if ( $data ) {
$script = "$data\n$script";
}
$wp_scripts->add_data( 'wp-plupload', 'data', $script );
}
/**
* Prepares an attachment post object for JS, where it is expected
* to be JSON-encoded and fit into an Attachment model.
*
* @since 3.5.0
*
* @param int|WP_Post $attachment Attachment ID or object.
* @return array|void {
* Array of attachment details, or void if the parameter does not correspond to an attachment.
*
* @type string $alt Alt text of the attachment.
* @type string $author ID of the attachment author, as a string.
* @type string $authorName Name of the attachment author.
* @type string $caption Caption for the attachment.
* @type array $compat Containing item and meta.
* @type string $context Context, whether it's used as the site icon for example.
* @type int $date Uploaded date, timestamp in milliseconds.
* @type string $dateFormatted Formatted date (e.g. June 29, 2018).
* @type string $description Description of the attachment.
* @type string $editLink URL to the edit page for the attachment.
* @type string $filename File name of the attachment.
* @type string $filesizeHumanReadable Filesize of the attachment in human readable format (e.g. 1 MB).
* @type int $filesizeInBytes Filesize of the attachment in bytes.
* @type int $height If the attachment is an image, represents the height of the image in pixels.
* @type string $icon Icon URL of the attachment (e.g. /wp-includes/images/media/archive.png).
* @type int $id ID of the attachment.
* @type string $link URL to the attachment.
* @type int $menuOrder Menu order of the attachment post.
* @type array $meta Meta data for the attachment.
* @type string $mime Mime type of the attachment (e.g. image/jpeg or application/zip).
* @type int $modified Last modified, timestamp in milliseconds.
* @type string $name Name, same as title of the attachment.
* @type array $nonces Nonces for update, delete and edit.
* @type string $orientation If the attachment is an image, represents the image orientation
* (landscape or portrait).
* @type array $sizes If the attachment is an image, contains an array of arrays
* for the images sizes: thumbnail, medium, large, and full.
* @type string $status Post status of the attachment (usually 'inherit').
* @type string $subtype Mime subtype of the attachment (usually the last part, e.g. jpeg or zip).
* @type string $title Title of the attachment (usually slugified file name without the extension).
* @type string $type Type of the attachment (usually first part of the mime type, e.g. image).
* @type int $uploadedTo Parent post to which the attachment was uploaded.
* @type string $uploadedToLink URL to the edit page of the parent post of the attachment.
* @type string $uploadedToTitle Post title of the parent of the attachment.
* @type string $url Direct URL to the attachment file (from wp-content).
* @type int $width If the attachment is an image, represents the width of the image in pixels.
* }
*/
function wp_prepare_attachment_for_js( $attachment ) {
$attachment = get_post( $attachment );
if ( ! $attachment ) {
return;
}
if ( 'attachment' !== $attachment->post_type ) {
return;
}
$meta = wp_get_attachment_metadata( $attachment->ID );
if ( str_contains( $attachment->post_mime_type, '/' ) ) {
list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
} else {
list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
}
$attachment_url = wp_get_attachment_url( $attachment->ID );
$base_url = str_replace( wp_basename( $attachment_url ), '', $attachment_url );
$response = array(
'id' => $attachment->ID,
'title' => $attachment->post_title,
'filename' => wp_basename( get_attached_file( $attachment->ID ) ),
'url' => $attachment_url,
'link' => get_attachment_link( $attachment->ID ),
'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
'author' => $attachment->post_author,
'description' => $attachment->post_content,
'caption' => $attachment->post_excerpt,
'name' => $attachment->post_name,
'status' => $attachment->post_status,
'uploadedTo' => $attachment->post_parent,
'date' => strtotime( $attachment->post_date_gmt ) * 1000,
'modified' => strtotime( $attachment->post_modified_gmt ) * 1000,
'menuOrder' => $attachment->menu_order,
'mime' => $attachment->post_mime_type,
'type' => $type,
'subtype' => $subtype,
'icon' => wp_mime_type_icon( $attachment->ID, '.svg' ),
'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ),
'nonces' => array(
'update' => false,
'delete' => false,
'edit' => false,
),
'editLink' => false,
'meta' => false,
);
$author = new WP_User( $attachment->post_author );
if ( $author->exists() ) {
$author_name = $author->display_name ? $author->display_name : $author->nickname;
$response['authorName'] = html_entity_decode( $author_name, ENT_QUOTES, get_bloginfo( 'charset' ) );
$response['authorLink'] = get_edit_user_link( $author->ID );
} else {
$response['authorName'] = __( '(no author)' );
}
if ( $attachment->post_parent ) {
$post_parent = get_post( $attachment->post_parent );
if ( $post_parent ) {
$response['uploadedToTitle'] = $post_parent->post_title ? $post_parent->post_title : __( '(no title)' );
$response['uploadedToLink'] = get_edit_post_link( $attachment->post_parent, 'raw' );
}
}
$attached_file = get_attached_file( $attachment->ID );
if ( isset( $meta['filesize'] ) ) {
$bytes = $meta['filesize'];
} elseif ( file_exists( $attached_file ) ) {
$bytes = wp_filesize( $attached_file );
} else {
$bytes = '';
}
if ( $bytes ) {
$response['filesizeInBytes'] = $bytes;
$response['filesizeHumanReadable'] = size_format( $bytes );
}
$context = get_post_meta( $attachment->ID, '_wp_attachment_context', true );
$response['context'] = ( $context ) ? $context : '';
if ( current_user_can( 'edit_post', $attachment->ID ) ) {
$response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
$response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
$response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
}
if ( current_user_can( 'delete_post', $attachment->ID ) ) {
$response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID );
}
if ( $meta && ( 'image' === $type || ! empty( $meta['sizes'] ) ) ) {
$sizes = array();
/** This filter is documented in wp-admin/includes/media.php */
$possible_sizes = apply_filters(
'image_size_names_choose',
array(
'thumbnail' => __( 'Thumbnail' ),
'medium' => __( 'Medium' ),
'large' => __( 'Large' ),
'full' => __( 'Full Size' ),
)
);
unset( $possible_sizes['full'] );
/*
* Loop through all potential sizes that may be chosen. Try to do this with some efficiency.
* First: run the image_downsize filter. If it returns something, we can use its data.
* If the filter does not return something, then image_downsize() is just an expensive way
* to check the image metadata, which we do second.
*/
foreach ( $possible_sizes as $size => $label ) {
/** This filter is documented in wp-includes/media.php */
$downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size );
if ( $downsize ) {
if ( empty( $downsize[3] ) ) {
continue;
}
$sizes[ $size ] = array(
'height' => $downsize[2],
'width' => $downsize[1],
'url' => $downsize[0],
'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape',
);
} elseif ( isset( $meta['sizes'][ $size ] ) ) {
// Nothing from the filter, so consult image metadata if we have it.
$size_meta = $meta['sizes'][ $size ];
/*
* We have the actual image size, but might need to further constrain it if content_width is narrower.
* Thumbnail, medium, and full sizes are also checked against the site's height/width options.
*/
list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' );
$sizes[ $size ] = array(
'height' => $height,
'width' => $width,
'url' => $base_url . $size_meta['file'],
'orientation' => $height > $width ? 'portrait' : 'landscape',
);
}
}
if ( 'image' === $type ) {
if ( ! empty( $meta['original_image'] ) ) {
$response['originalImageURL'] = wp_get_original_image_url( $attachment->ID );
$response['originalImageName'] = wp_basename( wp_get_original_image_path( $attachment->ID ) );
}
$sizes['full'] = array( 'url' => $attachment_url );
if ( isset( $meta['height'], $meta['width'] ) ) {
$sizes['full']['height'] = $meta['height'];
$sizes['full']['width'] = $meta['width'];
$sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape';
}
$response = array_merge( $response, $sizes['full'] );
} elseif ( $meta['sizes']['full']['file'] ) {
$sizes['full'] = array(
'url' => $base_url . $meta['sizes']['full']['file'],
'height' => $meta['sizes']['full']['height'],
'width' => $meta['sizes']['full']['width'],
'orientation' => $meta['sizes']['full']['height'] > $meta['sizes']['full']['width'] ? 'portrait' : 'landscape',
);
}
$response = array_merge( $response, array( 'sizes' => $sizes ) );
}
if ( $meta && 'video' === $type ) {
if ( isset( $meta['width'] ) ) {
$response['width'] = (int) $meta['width'];
}
if ( isset( $meta['height'] ) ) {
$response['height'] = (int) $meta['height'];
}
}
if ( $meta && ( 'audio' === $type || 'video' === $type ) ) {
if ( isset( $meta['length_formatted'] ) ) {
$response['fileLength'] = $meta['length_formatted'];
$response['fileLengthHumanReadable'] = human_readable_duration( $meta['length_formatted'] );
}
$response['meta'] = array();
foreach ( wp_get_attachment_id3_keys( $attachment, 'js' ) as $key => $label ) {
$response['meta'][ $key ] = false;
if ( ! empty( $meta[ $key ] ) ) {
$response['meta'][ $key ] = $meta[ $key ];
}
}
$id = get_post_thumbnail_id( $attachment->ID );
if ( ! empty( $id ) ) {
list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
$response['image'] = compact( 'src', 'width', 'height' );
list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' );
$response['thumb'] = compact( 'src', 'width', 'height' );
} else {
$src = wp_mime_type_icon( $attachment->ID, '.svg' );
$width = 48;
$height = 64;
$response['image'] = compact( 'src', 'width', 'height' );
$response['thumb'] = compact( 'src', 'width', 'height' );
}
}
if ( function_exists( 'get_compat_media_markup' ) ) {
$response['compat'] = get_compat_media_markup( $attachment->ID, array( 'in_modal' => true ) );
}
if ( function_exists( 'get_media_states' ) ) {
$media_states = get_media_states( $attachment );
if ( ! empty( $media_states ) ) {
$response['mediaStates'] = implode( ', ', $media_states );
}
}
/**
* Filters the attachment data prepared for JavaScript.
*
* @since 3.5.0
*
* @param array $response Array of prepared attachment data. See {@see wp_prepare_attachment_for_js()}.
* @param WP_Post $attachment Attachment object.
* @param array|false $meta Array of attachment meta data, or false if there is none.
*/
return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta );
}
/**
* Enqueues all scripts, styles, settings, and templates necessary to use
* all media JS APIs.
*
* @since 3.5.0
*
* @global int $content_width
* @global wpdb $wpdb WordPress database abstraction object.
* @global WP_Locale $wp_locale WordPress date and time locale object.
*
* @param array $args {
* Arguments for enqueuing media scripts.
*
* @type int|WP_Post $post Post ID or post object.
* }
*/
function wp_enqueue_media( $args = array() ) {
// Enqueue me just once per page, please.
if ( did_action( 'wp_enqueue_media' ) ) {
return;
}
global $content_width, $wpdb, $wp_locale;
$defaults = array(
'post' => null,
);
$args = wp_parse_args( $args, $defaults );
/*
* We're going to pass the old thickbox media tabs to `media_upload_tabs`
* to ensure plugins will work. We will then unset those tabs.
*/
$tabs = array(
// handler action suffix => tab label
'type' => '',
'type_url' => '',
'gallery' => '',
'library' => '',
);
/** This filter is documented in wp-admin/includes/media.php */
$tabs = apply_filters( 'media_upload_tabs', $tabs );
unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] );
$props = array(
'link' => get_option( 'image_default_link_type' ), // DB default is 'file'.
'align' => get_option( 'image_default_align' ), // Empty default.
'size' => get_option( 'image_default_size' ), // Empty default.
);
$exts = array_merge( wp_get_audio_extensions(), wp_get_video_extensions() );
$mimes = get_allowed_mime_types();
$ext_mimes = array();
foreach ( $exts as $ext ) {
foreach ( $mimes as $ext_preg => $mime_match ) {
if ( preg_match( '#' . $ext . '#i', $ext_preg ) ) {
$ext_mimes[ $ext ] = $mime_match;
break;
}
}
}
/**
* Allows showing or hiding the "Create Audio Playlist" button in the media library.
*
* By default, the "Create Audio Playlist" button will always be shown in
* the media library. If this filter returns `null`, a query will be run
* to determine whether the media library contains any audio items. This
* was the default behavior prior to version 4.8.0, but this query is
* expensive for large media libraries.
*
* @since 4.7.4
* @since 4.8.0 The filter's default value is `true` rather than `null`.
*
* @link https://core.trac.wordpress.org/ticket/31071
*
* @param bool|null $show Whether to show the button, or `null` to decide based
* on whether any audio files exist in the media library.
*/
$show_audio_playlist = apply_filters( 'media_library_show_audio_playlist', true );
if ( null === $show_audio_playlist ) {
$show_audio_playlist = $wpdb->get_var(
"SELECT ID
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'audio%'
LIMIT 1"
);
}
/**
* Allows showing or hiding the "Create Video Playlist" button in the media library.
*
* By default, the "Create Video Playlist" button will always be shown in
* the media library. If this filter returns `null`, a query will be run
* to determine whether the media library contains any video items. This
* was the default behavior prior to version 4.8.0, but this query is
* expensive for large media libraries.
*
* @since 4.7.4
* @since 4.8.0 The filter's default value is `true` rather than `null`.
*
* @link https://core.trac.wordpress.org/ticket/31071
*
* @param bool|null $show Whether to show the button, or `null` to decide based
* on whether any video files exist in the media library.
*/
$show_video_playlist = apply_filters( 'media_library_show_video_playlist', true );
if ( null === $show_video_playlist ) {
$show_video_playlist = $wpdb->get_var(
"SELECT ID
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'video%'
LIMIT 1"
);
}
/**
* Allows overriding the list of months displayed in the media library.
*
* By default (if this filter does not return an array), a query will be
* run to determine the months that have media items. This query can be
* expensive for large media libraries, so it may be desirable for sites to
* override this behavior.
*
* @since 4.7.4
*
* @link https://core.trac.wordpress.org/ticket/31071
*
* @param stdClass[]|null $months An array of objects with `month` and `year`
* properties, or `null` for default behavior.
*/
$months = apply_filters( 'media_library_months_with_files', null );
if ( ! is_array( $months ) ) {
$months = $wpdb->get_results(
$wpdb->prepare(
"SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
FROM $wpdb->posts
WHERE post_type = %s
ORDER BY post_date DESC",
'attachment'
)
);
}
foreach ( $months as $month_year ) {
$month_year->text = sprintf(
/* translators: 1: Month, 2: Year. */
__( '%1$s %2$d' ),
$wp_locale->get_month( $month_year->month ),
$month_year->year
);
}
/**
* Filters whether the Media Library grid has infinite scrolling. Default `false`.
*
* @since 5.8.0
*
* @param bool $infinite Whether the Media Library grid has infinite scrolling.
*/
$infinite_scrolling = apply_filters( 'media_library_infinite_scrolling', false );
$settings = array(
'tabs' => $tabs,
'tabUrl' => add_query_arg( array( 'chromeless' => true ), admin_url( 'media-upload.php' ) ),
'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ),
/** This filter is documented in wp-admin/includes/media.php */
'captions' => ! apply_filters( 'disable_captions', '' ),
'nonce' => array(
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ),
),
'post' => array(
'id' => 0,
),
'defaultProps' => $props,
'attachmentCounts' => array(
'audio' => ( $show_audio_playlist ) ? 1 : 0,
'video' => ( $show_video_playlist ) ? 1 : 0,
),
'oEmbedProxyUrl' => rest_url( 'oembed/1.0/proxy' ),
'embedExts' => $exts,
'embedMimes' => $ext_mimes,
'contentWidth' => $content_width,
'months' => $months,
'mediaTrash' => MEDIA_TRASH ? 1 : 0,
'infiniteScrolling' => ( $infinite_scrolling ) ? 1 : 0,
);
$post = null;
if ( isset( $args['post'] ) ) {
$post = get_post( $args['post'] );
$settings['post'] = array(
'id' => $post->ID,
'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
);
$thumbnail_support = current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' );
if ( ! $thumbnail_support && 'attachment' === $post->post_type && $post->post_mime_type ) {
if ( wp_attachment_is( 'audio', $post ) ) {
$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
} elseif ( wp_attachment_is( 'video', $post ) ) {
$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
}
}
if ( $thumbnail_support ) {
$featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
$settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
}
}
if ( $post ) {
$post_type_object = get_post_type_object( $post->post_type );
} else {
$post_type_object = get_post_type_object( 'post' );
}
$strings = array(
// Generic.
'mediaFrameDefaultTitle' => __( 'Media' ),
'url' => __( 'URL' ),
'addMedia' => __( 'Add media' ),
'search' => __( 'Search' ),
'select' => __( 'Select' ),
'cancel' => __( 'Cancel' ),
'update' => __( 'Update' ),
'replace' => __( 'Replace' ),
'remove' => __( 'Remove' ),
'back' => __( 'Back' ),
/*
* translators: This is a would-be plural string used in the media manager.
* If there is not a word you can use in your language to avoid issues with the
* lack of plural support here, turn it into "selected: %d" then translate it.
*/
'selected' => __( '%d selected' ),
'dragInfo' => __( 'Drag and drop to reorder media files.' ),
// Upload.
'uploadFilesTitle' => __( 'Upload files' ),
'uploadImagesTitle' => __( 'Upload images' ),
// Library.
'mediaLibraryTitle' => __( 'Media Library' ),
'insertMediaTitle' => __( 'Add media' ),
'createNewGallery' => __( 'Create a new gallery' ),
'createNewPlaylist' => __( 'Create a new playlist' ),
'createNewVideoPlaylist' => __( 'Create a new video playlist' ),
'returnToLibrary' => __( '← Go to library' ),
'allMediaItems' => __( 'All media items' ),
'allDates' => __( 'All dates' ),
'noItemsFound' => __( 'No items found.' ),
'insertIntoPost' => $post_type_object->labels->insert_into_item,
'unattached' => _x( 'Unattached', 'media items' ),
'mine' => _x( 'Mine', 'media items' ),
'trash' => _x( 'Trash', 'noun' ),
'uploadedToThisPost' => $post_type_object->labels->uploaded_to_this_item,
'warnDelete' => __( "You are about to permanently delete this item from your site.\nThis action cannot be undone.\n 'Cancel' to stop, 'OK' to delete." ),
'warnBulkDelete' => __( "You are about to permanently delete these items from your site.\nThis action cannot be undone.\n 'Cancel' to stop, 'OK' to delete." ),
'warnBulkTrash' => __( "You are about to trash these items.\n 'Cancel' to stop, 'OK' to delete." ),
'bulkSelect' => __( 'Bulk select' ),
'trashSelected' => __( 'Move to Trash' ),
'restoreSelected' => __( 'Restore from Trash' ),
'deletePermanently' => __( 'Delete permanently' ),
'errorDeleting' => __( 'Error in deleting the attachment.' ),
'apply' => __( 'Apply' ),
'filterByDate' => __( 'Filter by date' ),
'filterByType' => __( 'Filter by type' ),
'searchLabel' => __( 'Search media' ),
'searchMediaLabel' => __( 'Search media' ), // Backward compatibility pre-5.3.
'searchMediaPlaceholder' => __( 'Search media items...' ), // Placeholder (no ellipsis), backward compatibility pre-5.3.
/* translators: %d: Number of attachments found in a search. */
'mediaFound' => __( 'Number of media items found: %d' ),
'noMedia' => __( 'No media items found.' ),
'noMediaTryNewSearch' => __( 'No media items found. Try a different search.' ),
// Library Details.
'attachmentDetails' => __( 'Attachment details' ),
// From URL.
'insertFromUrlTitle' => __( 'Insert from URL' ),
// Featured Images.
'setFeaturedImageTitle' => $post_type_object->labels->featured_image,
'setFeaturedImage' => $post_type_object->labels->set_featured_image,
// Gallery.
'createGalleryTitle' => __( 'Create gallery' ),
'editGalleryTitle' => __( 'Edit gallery' ),
'cancelGalleryTitle' => __( '← Cancel gallery' ),
'insertGallery' => __( 'Insert gallery' ),
'updateGallery' => __( 'Update gallery' ),
'addToGallery' => __( 'Add to gallery' ),
'addToGalleryTitle' => __( 'Add to gallery' ),
'reverseOrder' => __( 'Reverse order' ),
// Edit Image.
'imageDetailsTitle' => __( 'Image details' ),
'imageReplaceTitle' => __( 'Replace image' ),
'imageDetailsCancel' => __( 'Cancel edit' ),
'editImage' => __( 'Edit image' ),
// Crop Image.
'chooseImage' => __( 'Choose image' ),
'selectAndCrop' => __( 'Select and crop' ),
'skipCropping' => __( 'Skip cropping' ),
'cropImage' => __( 'Crop image' ),
'cropYourImage' => __( 'Crop your image' ),
'cropping' => __( 'Cropping…' ),
/* translators: 1: Suggested width number, 2: Suggested height number. */
'suggestedDimensions' => __( 'Suggested image dimensions: %1$s by %2$s pixels.' ),
'cropError' => __( 'There has been an error cropping your image.' ),
// Edit Audio.
'audioDetailsTitle' => __( 'Audio details' ),
'audioReplaceTitle' => __( 'Replace audio' ),
'audioAddSourceTitle' => __( 'Add audio source' ),
'audioDetailsCancel' => __( 'Cancel edit' ),
// Edit Video.
'videoDetailsTitle' => __( 'Video details' ),
'videoReplaceTitle' => __( 'Replace video' ),
'videoAddSourceTitle' => __( 'Add video source' ),
'videoDetailsCancel' => __( 'Cancel edit' ),
'videoSelectPosterImageTitle' => __( 'Select poster image' ),
'videoAddTrackTitle' => __( 'Add subtitles' ),
// Playlist.
'playlistDragInfo' => __( 'Drag and drop to reorder tracks.' ),
'createPlaylistTitle' => __( 'Create audio playlist' ),
'editPlaylistTitle' => __( 'Edit audio playlist' ),
'cancelPlaylistTitle' => __( '← Cancel audio playlist' ),
'insertPlaylist' => __( 'Insert audio playlist' ),
'updatePlaylist' => __( 'Update audio playlist' ),
'addToPlaylist' => __( 'Add to audio playlist' ),
'addToPlaylistTitle' => __( 'Add to Audio Playlist' ),
// Video Playlist.
'videoPlaylistDragInfo' => __( 'Drag and drop to reorder videos.' ),
'createVideoPlaylistTitle' => __( 'Create video playlist' ),
'editVideoPlaylistTitle' => __( 'Edit video playlist' ),
'cancelVideoPlaylistTitle' => __( '← Cancel video playlist' ),
'insertVideoPlaylist' => __( 'Insert video playlist' ),
'updateVideoPlaylist' => __( 'Update video playlist' ),
'addToVideoPlaylist' => __( 'Add to video playlist' ),
'addToVideoPlaylistTitle' => __( 'Add to video Playlist' ),
// Headings.
'filterAttachments' => __( 'Filter media' ),
'attachmentsList' => __( 'Media list' ),
);
/**
* Filters the media view settings.
*
* @since 3.5.0
*
* @param array $settings List of media view settings.
* @param WP_Post $post Post object.
*/
$settings = apply_filters( 'media_view_settings', $settings, $post );
/**
* Filters the media view strings.
*
* @since 3.5.0
*
* @param string[] $strings Array of media view strings keyed by the name they'll be referenced by in JavaScript.
* @param WP_Post $post Post object.
*/
$strings = apply_filters( 'media_view_strings', $strings, $post );
$strings['settings'] = $settings;
/*
* Ensure we enqueue media-editor first, that way media-views
* is registered internally before we try to localize it. See #24724.
*/
wp_enqueue_script( 'media-editor' );
wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings );
wp_enqueue_script( 'media-audiovideo' );
wp_enqueue_style( 'media-views' );
if ( is_admin() ) {
wp_enqueue_script( 'mce-view' );
wp_enqueue_script( 'image-edit' );
}
wp_enqueue_style( 'imgareaselect' );
wp_plupload_default_settings();
require_once ABSPATH . WPINC . '/media-template.php';
add_action( 'admin_footer', 'wp_print_media_templates' );
add_action( 'wp_footer', 'wp_print_media_templates' );
add_action( 'customize_controls_print_footer_scripts', 'wp_print_media_templates' );
/**
* Fires at the conclusion of wp_enqueue_media().
*
* @since 3.5.0
*/
do_action( 'wp_enqueue_media' );
}
/**
* Retrieves media attached to the passed post.
*
* @since 3.6.0
*
* @param string $type Mime type.
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return WP_Post[] Array of media attached to the given post.
*/
function get_attached_media( $type, $post = 0 ) {
$post = get_post( $post );
if ( ! $post ) {
return array();
}
$args = array(
'post_parent' => $post->ID,
'post_type' => 'attachment',
'post_mime_type' => $type,
'posts_per_page' => -1,
'orderby' => 'menu_order',
'order' => 'ASC',
);
/**
* Filters arguments used to retrieve media attached to the given post.
*
* @since 3.6.0
*
* @param array $args Post query arguments.
* @param string $type Mime type of the desired media.
* @param WP_Post $post Post object.
*/
$args = apply_filters( 'get_attached_media_args', $args, $type, $post );
$children = get_children( $args );
/**
* Filters the list of media attached to the given post.
*
* @since 3.6.0
*
* @param WP_Post[] $children Array of media attached to the given post.
* @param string $type Mime type of the media desired.
* @param WP_Post $post Post object.
*/
return (array) apply_filters( 'get_attached_media', $children, $type, $post );
}
/**
* Checks the HTML content for an audio, video, object, embed, or iframe tags.
*
* @since 3.6.0
*
* @param string $content A string of HTML which might contain media elements.
* @param string[] $types An array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'.
* @return string[] Array of found HTML media elements.
*/
function get_media_embedded_in_content( $content, $types = null ) {
$html = array();
/**
* Filters the embedded media types that are allowed to be returned from the content blob.
*
* @since 4.2.0
*
* @param string[] $allowed_media_types An array of allowed media types. Default media types are
* 'audio', 'video', 'object', 'embed', and 'iframe'.
*/
$allowed_media_types = apply_filters( 'media_embedded_in_content_allowed_types', array( 'audio', 'video', 'object', 'embed', 'iframe' ) );
if ( ! empty( $types ) ) {
if ( ! is_array( $types ) ) {
$types = array( $types );
}
$allowed_media_types = array_intersect( $allowed_media_types, $types );
}
$tags = implode( '|', $allowed_media_types );
if ( preg_match_all( '#<(?P<tag>' . $tags . ')[^<]*?(?:>[\s\S]*?<\/(?P=tag)>|\s*\/>)#', $content, $matches ) ) {
foreach ( $matches[0] as $match ) {
$html[] = $match;
}
}
return $html;
}
/**
* Retrieves galleries from the passed post's content.
*
* @since 3.6.0
*
* @param int|WP_Post $post Post ID or object.
* @param bool $html Optional. Whether to return HTML or data in the array. Default true.
* @return array A list of arrays, each containing gallery data and srcs parsed
* from the expanded shortcode.
*/
function get_post_galleries( $post, $html = true ) {
$post = get_post( $post );
if ( ! $post ) {
return array();
}
if ( ! has_shortcode( $post->post_content, 'gallery' ) && ! has_block( 'gallery', $post->post_content ) ) {
return array();
}
$galleries = array();
if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $post->post_content, $matches, PREG_SET_ORDER ) ) {
foreach ( $matches as $shortcode ) {
if ( 'gallery' === $shortcode[2] ) {
$srcs = array();
$shortcode_attrs = shortcode_parse_atts( $shortcode[3] );
// Specify the post ID of the gallery we're viewing if the shortcode doesn't reference another post already.
if ( ! isset( $shortcode_attrs['id'] ) ) {
$shortcode[3] .= ' id="' . (int) $post->ID . '"';
}
$gallery = do_shortcode_tag( $shortcode );
if ( $html ) {
$galleries[] = $gallery;
} else {
preg_match_all( '#src=([\'"])(.+?)\1#is', $gallery, $src, PREG_SET_ORDER );
if ( ! empty( $src ) ) {
foreach ( $src as $s ) {
$srcs[] = $s[2];
}
}
$galleries[] = array_merge(
$shortcode_attrs,
array(
'src' => array_values( array_unique( $srcs ) ),
)
);
}
}
}
}
if ( has_block( 'gallery', $post->post_content ) ) {
$post_blocks = parse_blocks( $post->post_content );
while ( $block = array_shift( $post_blocks ) ) {
$has_inner_blocks = ! empty( $block['innerBlocks'] );
// Skip blocks with no blockName and no innerHTML.
if ( ! $block['blockName'] ) {
continue;
}
// Skip non-Gallery blocks.
if ( 'core/gallery' !== $block['blockName'] ) {
// Move inner blocks into the root array before skipping.
if ( $has_inner_blocks ) {
array_push( $post_blocks, ...$block['innerBlocks'] );
}
continue;
}
// New Gallery block format as HTML.
if ( $has_inner_blocks && $html ) {
$block_html = wp_list_pluck( $block['innerBlocks'], 'innerHTML' );
$galleries[] = '<figure>' . implode( ' ', $block_html ) . '</figure>';
continue;
}
$srcs = array();
// New Gallery block format as an array.
if ( $has_inner_blocks ) {
$attrs = wp_list_pluck( $block['innerBlocks'], 'attrs' );
$ids = wp_list_pluck( $attrs, 'id' );
foreach ( $ids as $id ) {
$url = wp_get_attachment_url( $id );
if ( is_string( $url ) && ! in_array( $url, $srcs, true ) ) {
$srcs[] = $url;
}
}
$galleries[] = array(
'ids' => implode( ',', $ids ),
'src' => $srcs,
);
continue;
}
// Old Gallery block format as HTML.
if ( $html ) {
$galleries[] = $block['innerHTML'];
continue;
}
// Old Gallery block format as an array.
$ids = ! empty( $block['attrs']['ids'] ) ? $block['attrs']['ids'] : array();
// If present, use the image IDs from the JSON blob as canonical.
if ( ! empty( $ids ) ) {
foreach ( $ids as $id ) {
$url = wp_get_attachment_url( $id );
if ( is_string( $url ) && ! in_array( $url, $srcs, true ) ) {
$srcs[] = $url;
}
}
$galleries[] = array(
'ids' => implode( ',', $ids ),
'src' => $srcs,
);
continue;
}
// Otherwise, extract srcs from the innerHTML.
preg_match_all( '#src=([\'"])(.+?)\1#is', $block['innerHTML'], $found_srcs, PREG_SET_ORDER );
if ( ! empty( $found_srcs[0] ) ) {
foreach ( $found_srcs as $src ) {
if ( isset( $src[2] ) && ! in_array( $src[2], $srcs, true ) ) {
$srcs[] = $src[2];
}
}
}
$galleries[] = array( 'src' => $srcs );
}
}
/**
* Filters the list of all found galleries in the given post.
*
* @since 3.6.0
*
* @param array $galleries Associative array of all found post galleries.
* @param WP_Post $post Post object.
*/
return apply_filters( 'get_post_galleries', $galleries, $post );
}
/**
* Checks a specified post's content for gallery and, if present, return the first
*
* @since 3.6.0
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @param bool $html Optional. Whether to return HTML or data. Default is true.
* @return string|array Gallery data and srcs parsed from the expanded shortcode.
*/
function get_post_gallery( $post = 0, $html = true ) {
$galleries = get_post_galleries( $post, $html );
$gallery = reset( $galleries );
/**
* Filters the first-found post gallery.
*
* @since 3.6.0
*
* @param array $gallery The first-found post gallery.
* @param int|WP_Post $post Post ID or object.
* @param array $galleries Associative array of all found post galleries.
*/
return apply_filters( 'get_post_gallery', $gallery, $post, $galleries );
}
/**
* Retrieves the image srcs from galleries from a post's content, if present.
*
* @since 3.6.0
*
* @see get_post_galleries()
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`.
* @return array A list of lists, each containing image srcs parsed.
* from an expanded shortcode
*/
function get_post_galleries_images( $post = 0 ) {
$galleries = get_post_galleries( $post, false );
return wp_list_pluck( $galleries, 'src' );
}
/**
* Checks a post's content for galleries and return the image srcs for the first found gallery.
*
* @since 3.6.0
*
* @see get_post_gallery()
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`.
* @return string[] A list of a gallery's image srcs in order.
*/
function get_post_gallery_images( $post = 0 ) {
$gallery = get_post_gallery( $post, false );
return empty( $gallery['src'] ) ? array() : $gallery['src'];
}
/**
* Maybe attempts to generate attachment metadata, if missing.
*
* @since 3.9.0
*
* @param WP_Post $attachment Attachment object.
*/
function wp_maybe_generate_attachment_metadata( $attachment ) {
if ( empty( $attachment ) || empty( $attachment->ID ) ) {
return;
}
$attachment_id = (int) $attachment->ID;
$file = get_attached_file( $attachment_id );
$meta = wp_get_attachment_metadata( $attachment_id );
if ( empty( $meta ) && file_exists( $file ) ) {
$_meta = get_post_meta( $attachment_id );
$_lock = 'wp_generating_att_' . $attachment_id;
if ( ! array_key_exists( '_wp_attachment_metadata', $_meta ) && ! get_transient( $_lock ) ) {
set_transient( $_lock, $file );
wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
delete_transient( $_lock );
}
}
}
/**
* Tries to convert an attachment URL into a post ID.
*
* @since 4.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $url The URL to resolve.
* @return int The found post ID, or 0 on failure.
*/
function attachment_url_to_postid( $url ) {
global $wpdb;
/**
* Filters the attachment ID to allow short-circuit the function.
*
* Allows plugins to short-circuit attachment ID lookups. Plugins making
* use of this function should return:
*
* - 0 (integer) to indicate the attachment is not found,
* - attachment ID (integer) to indicate the attachment ID found,
* - null to indicate WordPress should proceed with the lookup.
*
* Warning: The post ID may be null or zero, both of which cast to a
* boolean false. For information about casting to booleans see the
* {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}.
* Use the === operator for testing the post ID when developing filters using
* this hook.
*
* @since 6.7.0
*
* @param int|null $post_id The result of the post ID lookup. Null to indicate
* no lookup has been attempted. Default null.
* @param string $url The URL being looked up.
*/
$post_id = apply_filters( 'pre_attachment_url_to_postid', null, $url );
if ( null !== $post_id ) {
return (int) $post_id;
}
$dir = wp_get_upload_dir();
$path = $url;
$site_url = parse_url( $dir['url'] );
$image_path = parse_url( $path );
// Force the protocols to match if needed.
if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
$path = str_replace( $image_path['scheme'], $site_url['scheme'], $path );
}
if ( str_starts_with( $path, $dir['baseurl'] . '/' ) ) {
$path = substr( $path, strlen( $dir['baseurl'] . '/' ) );
}
$sql = $wpdb->prepare(
"SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
$path
);
$results = $wpdb->get_results( $sql );
$post_id = null;
if ( $results ) {
// Use the first available result, but prefer a case-sensitive match, if exists.
$post_id = reset( $results )->post_id;
if ( count( $results ) > 1 ) {
foreach ( $results as $result ) {
if ( $path === $result->meta_value ) {
$post_id = $result->post_id;
break;
}
}
}
}
/**
* Filters an attachment ID found by URL.
*
* @since 4.2.0
*
* @param int|null $post_id The post_id (if any) found by the function.
* @param string $url The URL being looked up.
*/
return (int) apply_filters( 'attachment_url_to_postid', $post_id, $url );
}
/**
* Returns the URLs for CSS files used in an iframe-sandbox'd TinyMCE media view.
*
* @since 4.0.0
*
* @return string[] The relevant CSS file URLs.
*/
function wpview_media_sandbox_styles() {
$version = 'ver=' . get_bloginfo( 'version' );
$mediaelement = includes_url( "js/mediaelement/mediaelementplayer-legacy.min.css?$version" );
$wpmediaelement = includes_url( "js/mediaelement/wp-mediaelement.css?$version" );
return array( $mediaelement, $wpmediaelement );
}
/**
* Registers the personal data exporter for media.
*
* @param array[] $exporters An array of personal data exporters, keyed by their ID.
* @return array[] Updated array of personal data exporters.
*/
function wp_register_media_personal_data_exporter( $exporters ) {
$exporters['wordpress-media'] = array(
'exporter_friendly_name' => __( 'WordPress Media' ),
'callback' => 'wp_media_personal_data_exporter',
);
return $exporters;
}
/**
* Finds and exports attachments associated with an email address.
*
* @since 4.9.6
*
* @param string $email_address The attachment owner email address.
* @param int $page Attachment page number.
* @return array {
* An array of personal data.
*
* @type array[] $data An array of personal data arrays.
* @type bool $done Whether the exporter is finished.
* }
*/
function wp_media_personal_data_exporter( $email_address, $page = 1 ) {
// Limit us to 50 attachments at a time to avoid timing out.
$number = 50;
$page = (int) $page;
$data_to_export = array();
$user = get_user_by( 'email', $email_address );
if ( false === $user ) {
return array(
'data' => $data_to_export,
'done' => true,
);
}
$post_query = new WP_Query(
array(
'author' => $user->ID,
'posts_per_page' => $number,
'paged' => $page,
'post_type' => 'attachment',
'post_status' => 'any',
'orderby' => 'ID',
'order' => 'ASC',
)
);
foreach ( (array) $post_query->posts as $post ) {
$attachment_url = wp_get_attachment_url( $post->ID );
if ( $attachment_url ) {
$post_data_to_export = array(
array(
'name' => __( 'URL' ),
'value' => $attachment_url,
),
);
$data_to_export[] = array(
'group_id' => 'media',
'group_label' => __( 'Media' ),
'group_description' => __( 'User’s media data.' ),
'item_id' => "post-{$post->ID}",
'data' => $post_data_to_export,
);
}
}
$done = $post_query->max_num_pages <= $page;
return array(
'data' => $data_to_export,
'done' => $done,
);
}
/**
* Adds additional default image sub-sizes.
*
* These sizes are meant to enhance the way WordPress displays images on the front-end on larger,
* high-density devices. They make it possible to generate more suitable `srcset` and `sizes` attributes
* when the users upload large images.
*
* The sizes can be changed or removed by themes and plugins but that is not recommended.
* The size "names" reflect the image dimensions, so changing the sizes would be quite misleading.
*
* @since 5.3.0
* @access private
*/
function _wp_add_additional_image_sizes() {
// 2x medium_large size.
add_image_size( '1536x1536', 1536, 1536 );
// 2x large size.
add_image_size( '2048x2048', 2048, 2048 );
}
/**
* Callback to enable showing of the user error when uploading .heic images.
*
* @since 5.5.0
* @since 6.7.0 The default behavior is to enable heic uploads as long as the server
* supports the format. The uploads are converted to JPEG's by default.
*
* @param array[] $plupload_settings The settings for Plupload.js.
* @return array[] Modified settings for Plupload.js.
*/
function wp_show_heic_upload_error( $plupload_settings ) {
// Check if HEIC images can be edited.
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/heic' ) ) ) {
$plupload_init['heic_upload_error'] = true;
}
return $plupload_settings;
}
/**
* Allows PHP's getimagesize() to be debuggable when necessary.
*
* @since 5.7.0
* @since 5.8.0 Added support for WebP images.
* @since 6.5.0 Added support for AVIF images.
*
* @param string $filename The file path.
* @param array $image_info Optional. Extended image information (passed by reference).
* @return array|false Array of image information or false on failure.
*/
function wp_getimagesize( $filename, ?array &$image_info = null ) {
// Don't silence errors when in debug mode, unless running unit tests.
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! defined( 'WP_RUN_CORE_TESTS' ) ) {
if ( 2 === func_num_args() ) {
$info = getimagesize( $filename, $image_info );
} else {
$info = getimagesize( $filename );
}
} else {
/*
* Silencing notice and warning is intentional.
*
* getimagesize() has a tendency to generate errors, such as
* "corrupt JPEG data: 7191 extraneous bytes before marker",
* even when it's able to provide image size information.
*
* See https://core.trac.wordpress.org/ticket/42480
*/
if ( 2 === func_num_args() ) {
$info = @getimagesize( $filename, $image_info );
} else {
$info = @getimagesize( $filename );
}
}
if (
! empty( $info ) &&
// Some PHP versions return 0x0 sizes from `getimagesize` for unrecognized image formats, including AVIFs.
! ( empty( $info[0] ) && empty( $info[1] ) )
) {
return $info;
}
$image_mime_type = wp_get_image_mime( $filename );
// Not an image?
if ( false === $image_mime_type ) {
return false;
}
/*
* For PHP versions that don't support WebP images,
* extract the image size info from the file headers.
*/
if ( 'image/webp' === $image_mime_type ) {
$webp_info = wp_get_webp_info( $filename );
$width = $webp_info['width'];
$height = $webp_info['height'];
// Mimic the native return format.
if ( $width && $height ) {
return array(
$width,
$height,
IMAGETYPE_WEBP,
sprintf(
'width="%d" height="%d"',
$width,
$height
),
'mime' => 'image/webp',
);
}
}
// For PHP versions that don't support AVIF images, extract the image size info from the file headers.
if ( 'image/avif' === $image_mime_type ) {
$avif_info = wp_get_avif_info( $filename );
$width = $avif_info['width'];
$height = $avif_info['height'];
// Mimic the native return format.
if ( $width && $height ) {
return array(
$width,
$height,
IMAGETYPE_AVIF,
sprintf(
'width="%d" height="%d"',
$width,
$height
),
'mime' => 'image/avif',
);
}
}
// For PHP versions that don't support HEIC images, extract the size info using Imagick when available.
if ( wp_is_heic_image_mime_type( $image_mime_type ) ) {
$editor = wp_get_image_editor( $filename );
if ( is_wp_error( $editor ) ) {
return false;
}
// If the editor for HEICs is Imagick, use it to get the image size.
if ( $editor instanceof WP_Image_Editor_Imagick ) {
$size = $editor->get_size();
return array(
$size['width'],
$size['height'],
IMAGETYPE_HEIC,
sprintf(
'width="%d" height="%d"',
$size['width'],
$size['height']
),
'mime' => 'image/heic',
);
}
}
// The image could not be parsed.
return false;
}
/**
* Extracts meta information about an AVIF file: width, height, bit depth, and number of channels.
*
* @since 6.5.0
*
* @param string $filename Path to an AVIF file.
* @return array {
* An array of AVIF image information.
*
* @type int|false $width Image width on success, false on failure.
* @type int|false $height Image height on success, false on failure.
* @type int|false $bit_depth Image bit depth on success, false on failure.
* @type int|false $num_channels Image number of channels on success, false on failure.
* }
*/
function wp_get_avif_info( $filename ) {
$results = array(
'width' => false,
'height' => false,
'bit_depth' => false,
'num_channels' => false,
);
if ( 'image/avif' !== wp_get_image_mime( $filename ) ) {
return $results;
}
// Parse the file using libavifinfo's PHP implementation.
require_once ABSPATH . WPINC . '/class-avif-info.php';
$handle = fopen( $filename, 'rb' );
if ( $handle ) {
$parser = new Avifinfo\Parser( $handle );
$success = $parser->parse_ftyp() && $parser->parse_file();
fclose( $handle );
if ( $success ) {
$results = $parser->features->primary_item_features;
}
}
return $results;
}
/**
* Extracts meta information about a WebP file: width, height, and type.
*
* @since 5.8.0
*
* @param string $filename Path to a WebP file.
* @return array {
* An array of WebP image information.
*
* @type int|false $width Image width on success, false on failure.
* @type int|false $height Image height on success, false on failure.
* @type string|false $type The WebP type: one of 'lossy', 'lossless' or 'animated-alpha'.
* False on failure.
* }
*/
function wp_get_webp_info( $filename ) {
$width = false;
$height = false;
$type = false;
if ( 'image/webp' !== wp_get_image_mime( $filename ) ) {
return compact( 'width', 'height', 'type' );
}
$magic = file_get_contents( $filename, false, null, 0, 40 );
if ( false === $magic ) {
return compact( 'width', 'height', 'type' );
}
// Make sure we got enough bytes.
if ( strlen( $magic ) < 40 ) {
return compact( 'width', 'height', 'type' );
}
/*
* The headers are a little different for each of the three formats.
* Header values based on WebP docs, see https://developers.google.com/speed/webp/docs/riff_container.
*/
switch ( substr( $magic, 12, 4 ) ) {
// Lossy WebP.
case 'VP8 ':
$parts = unpack( 'v2', substr( $magic, 26, 4 ) );
$width = (int) ( $parts[1] & 0x3FFF );
$height = (int) ( $parts[2] & 0x3FFF );
$type = 'lossy';
break;
// Lossless WebP.
case 'VP8L':
$parts = unpack( 'C4', substr( $magic, 21, 4 ) );
$width = (int) ( $parts[1] | ( ( $parts[2] & 0x3F ) << 8 ) ) + 1;
$height = (int) ( ( ( $parts[2] & 0xC0 ) >> 6 ) | ( $parts[3] << 2 ) | ( ( $parts[4] & 0x03 ) << 10 ) ) + 1;
$type = 'lossless';
break;
// Animated/alpha WebP.
case 'VP8X':
// Pad 24-bit int.
$width = unpack( 'V', substr( $magic, 24, 3 ) . "\x00" );
$width = (int) ( $width[1] & 0xFFFFFF ) + 1;
// Pad 24-bit int.
$height = unpack( 'V', substr( $magic, 27, 3 ) . "\x00" );
$height = (int) ( $height[1] & 0xFFFFFF ) + 1;
$type = 'animated-alpha';
break;
}
return compact( 'width', 'height', 'type' );
}
/**
* Gets loading optimization attributes.
*
* This function returns an array of attributes that should be merged into the given attributes array to optimize
* loading performance. Potential attributes returned by this function are:
* - `loading` attribute with a value of "lazy"
* - `fetchpriority` attribute with a value of "high"
* - `decoding` attribute with a value of "async"
*
* If any of these attributes are already present in the given attributes, they will not be modified. Note that no
* element should have both `loading="lazy"` and `fetchpriority="high"`, so the function will trigger a warning in case
* both attributes are present with those values.
*
* @since 6.3.0
*
* @global WP_Query $wp_query WordPress Query object.
*
* @param string $tag_name The tag name.
* @param array $attr Array of the attributes for the tag.
* @param string $context Context for the element for which the loading optimization attribute is requested.
* @return array Loading optimization attributes.
*/
function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
global $wp_query;
/**
* Filters whether to short-circuit loading optimization attributes.
*
* Returning an array from the filter will effectively short-circuit the loading of optimization attributes,
* returning that value instead.
*
* @since 6.4.0
*
* @param array|false $loading_attrs False by default, or array of loading optimization attributes to short-circuit.
* @param string $tag_name The tag name.
* @param array $attr Array of the attributes for the tag.
* @param string $context Context for the element for which the loading optimization attribute is requested.
*/
$loading_attrs = apply_filters( 'pre_wp_get_loading_optimization_attributes', false, $tag_name, $attr, $context );
if ( is_array( $loading_attrs ) ) {
return $loading_attrs;
}
$loading_attrs = array();
/*
* Skip lazy-loading for the overall block template, as it is handled more granularly.
* The skip is also applicable for `fetchpriority`.
*/
if ( 'template' === $context ) {
/** This filter is documented in wp-includes/media.php */
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}
// For now this function only supports images and iframes.
if ( 'img' !== $tag_name && 'iframe' !== $tag_name ) {
/** This filter is documented in wp-includes/media.php */
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}
/*
* Skip programmatically created images within content blobs as they need to be handled together with the other
* images within the post content or widget content.
* Without this clause, they would already be considered within their own context which skews the image count and
* can result in the first post content image being lazy-loaded or an image further down the page being marked as a
* high priority.
*/
if (
'the_content' !== $context && doing_filter( 'the_content' ) ||
'widget_text_content' !== $context && doing_filter( 'widget_text_content' ) ||
'widget_block_content' !== $context && doing_filter( 'widget_block_content' )
) {
/** This filter is documented in wp-includes/media.php */
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}
/*
* Add `decoding` with a value of "async" for every image unless it has a
* conflicting `decoding` attribute already present.
*/
if ( 'img' === $tag_name ) {
if ( isset( $attr['decoding'] ) ) {
$loading_attrs['decoding'] = $attr['decoding'];
} else {
$loading_attrs['decoding'] = 'async';
}
}
// For any resources, width and height must be provided, to avoid layout shifts.
if ( ! isset( $attr['width'], $attr['height'] ) ) {
/** This filter is documented in wp-includes/media.php */
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}
/*
* The key function logic starts here.
*/
$maybe_in_viewport = null;
$increase_count = false;
$maybe_increase_count = false;
// Logic to handle a `loading` attribute that is already provided.
if ( isset( $attr['loading'] ) ) {
/*
* Interpret "lazy" as not in viewport. Any other value can be
* interpreted as in viewport (realistically only "eager" or `false`
* to force-omit the attribute are other potential values).
*/
if ( 'lazy' === $attr['loading'] ) {
$maybe_in_viewport = false;
} else {
$maybe_in_viewport = true;
}
}
// Logic to handle a `fetchpriority` attribute that is already provided.
if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) {
/*
* If the image was already determined to not be in the viewport (e.g.
* from an already provided `loading` attribute), trigger a warning.
* Otherwise, the value can be interpreted as in viewport, since only
* the most important in-viewport image should have `fetchpriority` set
* to "high".
*/
if ( false === $maybe_in_viewport ) {
_doing_it_wrong(
__FUNCTION__,
__( 'An image should not be lazy-loaded and marked as high priority at the same time.' ),
'6.3.0'
);
/*
* Set `fetchpriority` here for backward-compatibility as we should
* not override what a developer decided, even though it seems
* incorrect.
*/
$loading_attrs['fetchpriority'] = 'high';
} else {
$maybe_in_viewport = true;
}
}
if ( null === $maybe_in_viewport ) {
$header_enforced_contexts = array(
'template_part_' . WP_TEMPLATE_PART_AREA_HEADER => true,
'get_header_image_tag' => true,
);
/**
* Filters the header-specific contexts.
*
* @since 6.4.0
*
* @param array $default_header_enforced_contexts Map of contexts for which elements should be considered
* in the header of the page, as $context => $enabled
* pairs. The $enabled should always be true.
*/
$header_enforced_contexts = apply_filters( 'wp_loading_optimization_force_header_contexts', $header_enforced_contexts );
// Consider elements with these header-specific contexts to be in viewport.
if ( isset( $header_enforced_contexts[ $context ] ) ) {
$maybe_in_viewport = true;
$maybe_increase_count = true;
} elseif ( ! is_admin() && in_the_loop() && is_main_query() ) {
/*
* Get the content media count, since this is a main query
* content element. This is accomplished by "increasing"
* the count by zero, as the only way to get the count is
* to call this function.
* The actual count increase happens further below, based
* on the `$increase_count` flag set here.
*/
$content_media_count = wp_increase_content_media_count( 0 );
$increase_count = true;
// If the count so far is below the threshold, `loading` attribute is omitted.
if ( $content_media_count < wp_omit_loading_attr_threshold() ) {
$maybe_in_viewport = true;
} else {
$maybe_in_viewport = false;
}
} elseif (
// Only apply for main query but before the loop.
$wp_query->before_loop && $wp_query->is_main_query()
/*
* Any image before the loop, but after the header has started should not be lazy-loaded,
* except when the footer has already started which can happen when the current template
* does not include any loop.
*/
&& did_action( 'get_header' ) && ! did_action( 'get_footer' )
) {
$maybe_in_viewport = true;
$maybe_increase_count = true;
}
}
/*
* If the element is in the viewport (`true`), potentially add
* `fetchpriority` with a value of "high". Otherwise, i.e. if the element
* is not not in the viewport (`false`) or it is unknown (`null`), add
* `loading` with a value of "lazy".
*/
if ( $maybe_in_viewport ) {
$loading_attrs = wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr );
} else {
// Only add `loading="lazy"` if the feature is enabled.
if ( wp_lazy_loading_enabled( $tag_name, $context ) ) {
$loading_attrs['loading'] = 'lazy';
}
}
/*
* If flag was set based on contextual logic above, increase the content
* media count, either unconditionally, or based on whether the image size
* is larger than the threshold.
*/
if ( $increase_count ) {
wp_increase_content_media_count();
} elseif ( $maybe_increase_count ) {
/** This filter is documented in wp-includes/media.php */
$wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 );
if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) {
wp_increase_content_media_count();
}
}
/**
* Filters the loading optimization attributes.
*
* @since 6.4.0
*
* @param array $loading_attrs The loading optimization attributes.
* @param string $tag_name The tag name.
* @param array $attr Array of the attributes for the tag.
* @param string $context Context for the element for which the loading optimization attribute is requested.
*/
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}
/**
* Gets the threshold for how many of the first content media elements to not lazy-load.
*
* This function runs the {@see 'wp_omit_loading_attr_threshold'} filter, which uses a default threshold value of 3.
* The filter is only run once per page load, unless the `$force` parameter is used.
*
* @since 5.9.0
*
* @param bool $force Optional. If set to true, the filter will be (re-)applied even if it already has been before.
* Default false.
* @return int The number of content media elements to not lazy-load.
*/
function wp_omit_loading_attr_threshold( $force = false ) {
static $omit_threshold;
// This function may be called multiple times. Run the filter only once per page load.
if ( ! isset( $omit_threshold ) || $force ) {
/**
* Filters the threshold for how many of the first content media elements to not lazy-load.
*
* For these first content media elements, the `loading` attribute will be omitted. By default, this is the case
* for only the very first content media element.
*
* @since 5.9.0
* @since 6.3.0 The default threshold was changed from 1 to 3.
*
* @param int $omit_threshold The number of media elements where the `loading` attribute will not be added. Default 3.
*/
$omit_threshold = apply_filters( 'wp_omit_loading_attr_threshold', 3 );
}
return $omit_threshold;
}
/**
* Increases an internal content media count variable.
*
* @since 5.9.0
* @access private
*
* @param int $amount Optional. Amount to increase by. Default 1.
* @return int The latest content media count, after the increase.
*/
function wp_increase_content_media_count( $amount = 1 ) {
static $content_media_count = 0;
$content_media_count += $amount;
return $content_media_count;
}
/**
* Determines whether to add `fetchpriority='high'` to loading attributes.
*
* @since 6.3.0
* @access private
*
* @param array $loading_attrs Array of the loading optimization attributes for the element.
* @param string $tag_name The tag name.
* @param array $attr Array of the attributes for the element.
* @return array Updated loading optimization attributes for the element.
*/
function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ) {
// For now, adding `fetchpriority="high"` is only supported for images.
if ( 'img' !== $tag_name ) {
return $loading_attrs;
}
if ( isset( $attr['fetchpriority'] ) ) {
/*
* While any `fetchpriority` value could be set in `$loading_attrs`,
* for consistency we only do it for `fetchpriority="high"` since that
* is the only possible value that WordPress core would apply on its
* own.
*/
if ( 'high' === $attr['fetchpriority'] ) {
$loading_attrs['fetchpriority'] = 'high';
wp_high_priority_element_flag( false );
}
return $loading_attrs;
}
// Lazy-loading and `fetchpriority="high"` are mutually exclusive.
if ( isset( $loading_attrs['loading'] ) && 'lazy' === $loading_attrs['loading'] ) {
return $loading_attrs;
}
if ( ! wp_high_priority_element_flag() ) {
return $loading_attrs;
}
/**
* Filters the minimum square-pixels threshold for an image to be eligible as the high-priority image.
*
* @since 6.3.0
*
* @param int $threshold Minimum square-pixels threshold. Default 50000.
*/
$wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 );
if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) {
$loading_attrs['fetchpriority'] = 'high';
wp_high_priority_element_flag( false );
}
return $loading_attrs;
}
/**
* Accesses a flag that indicates if an element is a possible candidate for `fetchpriority='high'`.
*
* @since 6.3.0
* @access private
*
* @param bool $value Optional. Used to change the static variable. Default null.
* @return bool Returns true if high-priority element was marked already, otherwise false.
*/
function wp_high_priority_element_flag( $value = null ) {
static $high_priority_element = true;
if ( is_bool( $value ) ) {
$high_priority_element = $value;
}
return $high_priority_element;
}
/**
* Determines the output format for the image editor.
*
* @since 6.7.0
* @access private
*
* @param string $filename Path to the image.
* @param string $mime_type The source image mime type.
* @return string[] An array of mime type mappings.
*/
function wp_get_image_editor_output_format( $filename, $mime_type ) {
$output_format = array(
'image/heic' => 'image/jpeg',
'image/heif' => 'image/jpeg',
'image/heic-sequence' => 'image/jpeg',
'image/heif-sequence' => 'image/jpeg',
);
/**
* Filters the image editor output format mapping.
*
* Enables filtering the mime type used to save images. By default HEIC/HEIF images
* are converted to JPEGs.
*
* @see WP_Image_Editor::get_output_format()
*
* @since 5.8.0
* @since 6.7.0 The default was changed from an empty array to an array
* containing the HEIC/HEIF images mime types.
*
* @param string[] $output_format {
* An array of mime type mappings. Maps a source mime type to a new
* destination mime type. By default maps HEIC/HEIF input to JPEG output.
*
* @type string ...$0 The new mime type.
* }
* @param string $filename Path to the image.
* @param string $mime_type The source image mime type.
*/
return apply_filters( 'image_editor_output_format', $output_format, $filename, $mime_type );
}
<?php
/**
* Dependencies API: WP_Styles class
*
* This file is deprecated, use 'wp-includes/class-wp-styles.php' instead.
*
* @deprecated 6.1.0
* @package WordPress
*/
_deprecated_file( basename( __FILE__ ), '6.1.0', WPINC . '/class-wp-styles.php' );
/** WP_Styles class */
require_once ABSPATH . WPINC . '/class-wp-styles.php';
[02-Dec-2025 10:42:16 America/Bogota] PHP Fatal error: Uncaught Error: Undefined constant "ABSPATH" in /home/coopserp/public_html/wp-includes/Requests/library/Requests.php:12
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/library/Requests.php on line 12
<?php
/**
* Loads the old Requests class file when the autoloader
* references the original PSR-0 Requests class.
*
* @deprecated 6.2.0
* @package WordPress
* @subpackage Requests
* @since 6.2.0
*/
include_once ABSPATH . WPINC . '/class-requests.php';
<?php
/**
* IRI parser/serialiser/normaliser
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Ipv6;
use WpOrg\Requests\Port;
use WpOrg\Requests\Utility\InputValidator;
/**
* IRI parser/serialiser/normaliser
*
* Copyright (c) 2007-2010, Geoffrey Sneddon and Steve Minutillo.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the SimplePie Team nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Requests\Utilities
* @author Geoffrey Sneddon
* @author Steve Minutillo
* @copyright 2007-2009 Geoffrey Sneddon and Steve Minutillo
* @license https://opensource.org/licenses/bsd-license.php
* @link http://hg.gsnedders.com/iri/
*
* @property string $iri IRI we're working with
* @property-read string $uri IRI in URI form, {@see \WpOrg\Requests\Iri::to_uri()}
* @property string $scheme Scheme part of the IRI
* @property string $authority Authority part, formatted for a URI (userinfo + host + port)
* @property string $iauthority Authority part of the IRI (userinfo + host + port)
* @property string $userinfo Userinfo part, formatted for a URI (after '://' and before '@')
* @property string $iuserinfo Userinfo part of the IRI (after '://' and before '@')
* @property string $host Host part, formatted for a URI
* @property string $ihost Host part of the IRI
* @property string $port Port part of the IRI (after ':')
* @property string $path Path part, formatted for a URI (after first '/')
* @property string $ipath Path part of the IRI (after first '/')
* @property string $query Query part, formatted for a URI (after '?')
* @property string $iquery Query part of the IRI (after '?')
* @property string $fragment Fragment, formatted for a URI (after '#')
* @property string $ifragment Fragment part of the IRI (after '#')
*/
class Iri {
/**
* Scheme
*
* @var string|null
*/
protected $scheme = null;
/**
* User Information
*
* @var string|null
*/
protected $iuserinfo = null;
/**
* ihost
*
* @var string|null
*/
protected $ihost = null;
/**
* Port
*
* @var string|null
*/
protected $port = null;
/**
* ipath
*
* @var string
*/
protected $ipath = '';
/**
* iquery
*
* @var string|null
*/
protected $iquery = null;
/**
* ifragment|null
*
* @var string
*/
protected $ifragment = null;
/**
* Normalization database
*
* Each key is the scheme, each value is an array with each key as the IRI
* part and value as the default value for that part.
*
* @var array
*/
protected $normalization = array(
'acap' => array(
'port' => Port::ACAP,
),
'dict' => array(
'port' => Port::DICT,
),
'file' => array(
'ihost' => 'localhost',
),
'http' => array(
'port' => Port::HTTP,
),
'https' => array(
'port' => Port::HTTPS,
),
);
/**
* Return the entire IRI when you try and read the object as a string
*
* @return string
*/
public function __toString() {
return $this->get_iri();
}
/**
* Overload __set() to provide access via properties
*
* @param string $name Property name
* @param mixed $value Property value
*/
public function __set($name, $value) {
if (method_exists($this, 'set_' . $name)) {
call_user_func(array($this, 'set_' . $name), $value);
}
elseif (
$name === 'iauthority'
|| $name === 'iuserinfo'
|| $name === 'ihost'
|| $name === 'ipath'
|| $name === 'iquery'
|| $name === 'ifragment'
) {
call_user_func(array($this, 'set_' . substr($name, 1)), $value);
}
}
/**
* Overload __get() to provide access via properties
*
* @param string $name Property name
* @return mixed
*/
public function __get($name) {
// isset() returns false for null, we don't want to do that
// Also why we use array_key_exists below instead of isset()
$props = get_object_vars($this);
if (
$name === 'iri' ||
$name === 'uri' ||
$name === 'iauthority' ||
$name === 'authority'
) {
$method = 'get_' . $name;
$return = $this->$method();
}
elseif (array_key_exists($name, $props)) {
$return = $this->$name;
}
// host -> ihost
elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) {
$name = $prop;
$return = $this->$prop;
}
// ischeme -> scheme
elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) {
$name = $prop;
$return = $this->$prop;
}
else {
trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
$return = null;
}
if ($return === null && isset($this->normalization[$this->scheme][$name])) {
return $this->normalization[$this->scheme][$name];
}
else {
return $return;
}
}
/**
* Overload __isset() to provide access via properties
*
* @param string $name Property name
* @return bool
*/
public function __isset($name) {
return (method_exists($this, 'get_' . $name) || isset($this->$name));
}
/**
* Overload __unset() to provide access via properties
*
* @param string $name Property name
*/
public function __unset($name) {
if (method_exists($this, 'set_' . $name)) {
call_user_func(array($this, 'set_' . $name), '');
}
}
/**
* Create a new IRI object, from a specified string
*
* @param string|Stringable|null $iri
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $iri argument is not a string, Stringable or null.
*/
public function __construct($iri = null) {
if ($iri !== null && InputValidator::is_string_or_stringable($iri) === false) {
throw InvalidArgument::create(1, '$iri', 'string|Stringable|null', gettype($iri));
}
$this->set_iri($iri);
}
/**
* Create a new IRI object by resolving a relative IRI
*
* Returns false if $base is not absolute, otherwise an IRI.
*
* @param \WpOrg\Requests\Iri|string $base (Absolute) Base IRI
* @param \WpOrg\Requests\Iri|string $relative Relative IRI
* @return \WpOrg\Requests\Iri|false
*/
public static function absolutize($base, $relative) {
if (!($relative instanceof self)) {
$relative = new self($relative);
}
if (!$relative->is_valid()) {
return false;
}
elseif ($relative->scheme !== null) {
return clone $relative;
}
if (!($base instanceof self)) {
$base = new self($base);
}
if ($base->scheme === null || !$base->is_valid()) {
return false;
}
if ($relative->get_iri() !== '') {
if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) {
$target = clone $relative;
$target->scheme = $base->scheme;
}
else {
$target = new self;
$target->scheme = $base->scheme;
$target->iuserinfo = $base->iuserinfo;
$target->ihost = $base->ihost;
$target->port = $base->port;
if ($relative->ipath !== '') {
if ($relative->ipath[0] === '/') {
$target->ipath = $relative->ipath;
}
elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') {
$target->ipath = '/' . $relative->ipath;
}
elseif (($last_segment = strrpos($base->ipath, '/')) !== false) {
$target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
}
else {
$target->ipath = $relative->ipath;
}
$target->ipath = $target->remove_dot_segments($target->ipath);
$target->iquery = $relative->iquery;
}
else {
$target->ipath = $base->ipath;
if ($relative->iquery !== null) {
$target->iquery = $relative->iquery;
}
elseif ($base->iquery !== null) {
$target->iquery = $base->iquery;
}
}
$target->ifragment = $relative->ifragment;
}
}
else {
$target = clone $base;
$target->ifragment = null;
}
$target->scheme_normalization();
return $target;
}
/**
* Parse an IRI into scheme/authority/path/query/fragment segments
*
* @param string $iri
* @return array
*/
protected function parse_iri($iri) {
$iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
$has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match);
if (!$has_match) {
throw new Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
}
if ($match[1] === '') {
$match['scheme'] = null;
}
if (!isset($match[3]) || $match[3] === '') {
$match['authority'] = null;
}
if (!isset($match[5])) {
$match['path'] = '';
}
if (!isset($match[6]) || $match[6] === '') {
$match['query'] = null;
}
if (!isset($match[8]) || $match[8] === '') {
$match['fragment'] = null;
}
return $match;
}
/**
* Remove dot segments from a path
*
* @param string $input
* @return string
*/
protected function remove_dot_segments($input) {
$output = '';
while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') {
// A: If the input buffer begins with a prefix of "../" or "./",
// then remove that prefix from the input buffer; otherwise,
if (strpos($input, '../') === 0) {
$input = substr($input, 3);
}
elseif (strpos($input, './') === 0) {
$input = substr($input, 2);
}
// B: if the input buffer begins with a prefix of "/./" or "/.",
// where "." is a complete path segment, then replace that prefix
// with "/" in the input buffer; otherwise,
elseif (strpos($input, '/./') === 0) {
$input = substr($input, 2);
}
elseif ($input === '/.') {
$input = '/';
}
// C: if the input buffer begins with a prefix of "/../" or "/..",
// where ".." is a complete path segment, then replace that prefix
// with "/" in the input buffer and remove the last segment and its
// preceding "/" (if any) from the output buffer; otherwise,
elseif (strpos($input, '/../') === 0) {
$input = substr($input, 3);
$output = substr_replace($output, '', (strrpos($output, '/') ?: 0));
}
elseif ($input === '/..') {
$input = '/';
$output = substr_replace($output, '', (strrpos($output, '/') ?: 0));
}
// D: if the input buffer consists only of "." or "..", then remove
// that from the input buffer; otherwise,
elseif ($input === '.' || $input === '..') {
$input = '';
}
// E: move the first path segment in the input buffer to the end of
// the output buffer, including the initial "/" character (if any)
// and any subsequent characters up to, but not including, the next
// "/" character or the end of the input buffer
elseif (($pos = strpos($input, '/', 1)) !== false) {
$output .= substr($input, 0, $pos);
$input = substr_replace($input, '', 0, $pos);
}
else {
$output .= $input;
$input = '';
}
}
return $output . $input;
}
/**
* Replace invalid character with percent encoding
*
* @param string $text Input string
* @param string $extra_chars Valid characters not in iunreserved or
* iprivate (this is ASCII-only)
* @param bool $iprivate Allow iprivate
* @return string
*/
protected function replace_invalid_with_pct_encoding($text, $extra_chars, $iprivate = false) {
// Normalize as many pct-encoded sections as possible
$text = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $text);
// Replace invalid percent characters
$text = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $text);
// Add unreserved and % to $extra_chars (the latter is safe because all
// pct-encoded sections are now valid).
$extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
// Now replace any bytes that aren't allowed with their pct-encoded versions
$position = 0;
$strlen = strlen($text);
while (($position += strspn($text, $extra_chars, $position)) < $strlen) {
$value = ord($text[$position]);
// Start position
$start = $position;
// By default we are valid
$valid = true;
// No one byte sequences are valid due to the while.
// Two byte sequence:
if (($value & 0xE0) === 0xC0) {
$character = ($value & 0x1F) << 6;
$length = 2;
$remaining = 1;
}
// Three byte sequence:
elseif (($value & 0xF0) === 0xE0) {
$character = ($value & 0x0F) << 12;
$length = 3;
$remaining = 2;
}
// Four byte sequence:
elseif (($value & 0xF8) === 0xF0) {
$character = ($value & 0x07) << 18;
$length = 4;
$remaining = 3;
}
// Invalid byte:
else {
$valid = false;
$length = 1;
$remaining = 0;
}
if ($remaining) {
if ($position + $length <= $strlen) {
for ($position++; $remaining; $position++) {
$value = ord($text[$position]);
// Check that the byte is valid, then add it to the character:
if (($value & 0xC0) === 0x80) {
$character |= ($value & 0x3F) << (--$remaining * 6);
}
// If it is invalid, count the sequence as invalid and reprocess the current byte:
else {
$valid = false;
$position--;
break;
}
}
}
else {
$position = $strlen - 1;
$valid = false;
}
}
// Percent encode anything invalid or not in ucschar
if (
// Invalid sequences
!$valid
// Non-shortest form sequences are invalid
|| $length > 1 && $character <= 0x7F
|| $length > 2 && $character <= 0x7FF
|| $length > 3 && $character <= 0xFFFF
// Outside of range of ucschar codepoints
// Noncharacters
|| ($character & 0xFFFE) === 0xFFFE
|| $character >= 0xFDD0 && $character <= 0xFDEF
|| (
// Everything else not in ucschar
$character > 0xD7FF && $character < 0xF900
|| $character < 0xA0
|| $character > 0xEFFFD
)
&& (
// Everything not in iprivate, if it applies
!$iprivate
|| $character < 0xE000
|| $character > 0x10FFFD
)
) {
// If we were a character, pretend we weren't, but rather an error.
if ($valid) {
$position--;
}
for ($j = $start; $j <= $position; $j++) {
$text = substr_replace($text, sprintf('%%%02X', ord($text[$j])), $j, 1);
$j += 2;
$position += 2;
$strlen += 2;
}
}
}
return $text;
}
/**
* Callback function for preg_replace_callback.
*
* Removes sequences of percent encoded bytes that represent UTF-8
* encoded characters in iunreserved
*
* @param array $regex_match PCRE match
* @return string Replacement
*/
protected function remove_iunreserved_percent_encoded($regex_match) {
// As we just have valid percent encoded sequences we can just explode
// and ignore the first member of the returned array (an empty string).
$bytes = explode('%', $regex_match[0]);
// Initialize the new string (this is what will be returned) and that
// there are no bytes remaining in the current sequence (unsurprising
// at the first byte!).
$string = '';
$remaining = 0;
// Loop over each and every byte, and set $value to its value
for ($i = 1, $len = count($bytes); $i < $len; $i++) {
$value = hexdec($bytes[$i]);
// If we're the first byte of sequence:
if (!$remaining) {
// Start position
$start = $i;
// By default we are valid
$valid = true;
// One byte sequence:
if ($value <= 0x7F) {
$character = $value;
$length = 1;
}
// Two byte sequence:
elseif (($value & 0xE0) === 0xC0) {
$character = ($value & 0x1F) << 6;
$length = 2;
$remaining = 1;
}
// Three byte sequence:
elseif (($value & 0xF0) === 0xE0) {
$character = ($value & 0x0F) << 12;
$length = 3;
$remaining = 2;
}
// Four byte sequence:
elseif (($value & 0xF8) === 0xF0) {
$character = ($value & 0x07) << 18;
$length = 4;
$remaining = 3;
}
// Invalid byte:
else {
$valid = false;
$remaining = 0;
}
}
// Continuation byte:
else {
// Check that the byte is valid, then add it to the character:
if (($value & 0xC0) === 0x80) {
$remaining--;
$character |= ($value & 0x3F) << ($remaining * 6);
}
// If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
else {
$valid = false;
$remaining = 0;
$i--;
}
}
// If we've reached the end of the current byte sequence, append it to Unicode::$data
if (!$remaining) {
// Percent encode anything invalid or not in iunreserved
if (
// Invalid sequences
!$valid
// Non-shortest form sequences are invalid
|| $length > 1 && $character <= 0x7F
|| $length > 2 && $character <= 0x7FF
|| $length > 3 && $character <= 0xFFFF
// Outside of range of iunreserved codepoints
|| $character < 0x2D
|| $character > 0xEFFFD
// Noncharacters
|| ($character & 0xFFFE) === 0xFFFE
|| $character >= 0xFDD0 && $character <= 0xFDEF
// Everything else not in iunreserved (this is all BMP)
|| $character === 0x2F
|| $character > 0x39 && $character < 0x41
|| $character > 0x5A && $character < 0x61
|| $character > 0x7A && $character < 0x7E
|| $character > 0x7E && $character < 0xA0
|| $character > 0xD7FF && $character < 0xF900
) {
for ($j = $start; $j <= $i; $j++) {
$string .= '%' . strtoupper($bytes[$j]);
}
}
else {
for ($j = $start; $j <= $i; $j++) {
$string .= chr(hexdec($bytes[$j]));
}
}
}
}
// If we have any bytes left over they are invalid (i.e., we are
// mid-way through a multi-byte sequence)
if ($remaining) {
for ($j = $start; $j < $len; $j++) {
$string .= '%' . strtoupper($bytes[$j]);
}
}
return $string;
}
protected function scheme_normalization() {
if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) {
$this->iuserinfo = null;
}
if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) {
$this->ihost = null;
}
if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) {
$this->port = null;
}
if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) {
$this->ipath = '';
}
if (isset($this->ihost) && empty($this->ipath)) {
$this->ipath = '/';
}
if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) {
$this->iquery = null;
}
if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) {
$this->ifragment = null;
}
}
/**
* Check if the object represents a valid IRI. This needs to be done on each
* call as some things change depending on another part of the IRI.
*
* @return bool
*/
public function is_valid() {
$isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
if ($this->ipath !== '' &&
(
$isauthority && $this->ipath[0] !== '/' ||
(
$this->scheme === null &&
!$isauthority &&
strpos($this->ipath, ':') !== false &&
(strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
)
)
) {
return false;
}
return true;
}
public function __wakeup() {
$class_props = get_class_vars( __CLASS__ );
$string_props = array( 'scheme', 'iuserinfo', 'ihost', 'port', 'ipath', 'iquery', 'ifragment' );
$array_props = array( 'normalization' );
foreach ( $class_props as $prop => $default_value ) {
if ( in_array( $prop, $string_props, true ) && ! is_string( $this->$prop ) ) {
throw new UnexpectedValueException();
} elseif ( in_array( $prop, $array_props, true ) && ! is_array( $this->$prop ) ) {
throw new UnexpectedValueException();
}
$this->$prop = null;
}
}
/**
* Set the entire IRI. Returns true on success, false on failure (if there
* are any invalid characters).
*
* @param string $iri
* @return bool
*/
protected function set_iri($iri) {
static $cache;
if (!$cache) {
$cache = array();
}
if ($iri === null) {
return true;
}
$iri = (string) $iri;
if (isset($cache[$iri])) {
list($this->scheme,
$this->iuserinfo,
$this->ihost,
$this->port,
$this->ipath,
$this->iquery,
$this->ifragment,
$return) = $cache[$iri];
return $return;
}
$parsed = $this->parse_iri($iri);
$return = $this->set_scheme($parsed['scheme'])
&& $this->set_authority($parsed['authority'])
&& $this->set_path($parsed['path'])
&& $this->set_query($parsed['query'])
&& $this->set_fragment($parsed['fragment']);
$cache[$iri] = array($this->scheme,
$this->iuserinfo,
$this->ihost,
$this->port,
$this->ipath,
$this->iquery,
$this->ifragment,
$return);
return $return;
}
/**
* Set the scheme. Returns true on success, false on failure (if there are
* any invalid characters).
*
* @param string $scheme
* @return bool
*/
protected function set_scheme($scheme) {
if ($scheme === null) {
$this->scheme = null;
}
elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) {
$this->scheme = null;
return false;
}
else {
$this->scheme = strtolower($scheme);
}
return true;
}
/**
* Set the authority. Returns true on success, false on failure (if there are
* any invalid characters).
*
* @param string $authority
* @return bool
*/
protected function set_authority($authority) {
static $cache;
if (!$cache) {
$cache = array();
}
if ($authority === null) {
$this->iuserinfo = null;
$this->ihost = null;
$this->port = null;
return true;
}
if (isset($cache[$authority])) {
list($this->iuserinfo,
$this->ihost,
$this->port,
$return) = $cache[$authority];
return $return;
}
$remaining = $authority;
if (($iuserinfo_end = strrpos($remaining, '@')) !== false) {
$iuserinfo = substr($remaining, 0, $iuserinfo_end);
$remaining = substr($remaining, $iuserinfo_end + 1);
}
else {
$iuserinfo = null;
}
if (($port_start = strpos($remaining, ':', (strpos($remaining, ']') ?: 0))) !== false) {
$port = substr($remaining, $port_start + 1);
if ($port === false || $port === '') {
$port = null;
}
$remaining = substr($remaining, 0, $port_start);
}
else {
$port = null;
}
$return = $this->set_userinfo($iuserinfo) &&
$this->set_host($remaining) &&
$this->set_port($port);
$cache[$authority] = array($this->iuserinfo,
$this->ihost,
$this->port,
$return);
return $return;
}
/**
* Set the iuserinfo.
*
* @param string $iuserinfo
* @return bool
*/
protected function set_userinfo($iuserinfo) {
if ($iuserinfo === null) {
$this->iuserinfo = null;
}
else {
$this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
$this->scheme_normalization();
}
return true;
}
/**
* Set the ihost. Returns true on success, false on failure (if there are
* any invalid characters).
*
* @param string $ihost
* @return bool
*/
protected function set_host($ihost) {
if ($ihost === null) {
$this->ihost = null;
return true;
}
if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') {
if (Ipv6::check_ipv6(substr($ihost, 1, -1))) {
$this->ihost = '[' . Ipv6::compress(substr($ihost, 1, -1)) . ']';
}
else {
$this->ihost = null;
return false;
}
}
else {
$ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
// Lowercase, but ignore pct-encoded sections (as they should
// remain uppercase). This must be done after the previous step
// as that can add unescaped characters.
$position = 0;
$strlen = strlen($ihost);
while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) {
if ($ihost[$position] === '%') {
$position += 3;
}
else {
$ihost[$position] = strtolower($ihost[$position]);
$position++;
}
}
$this->ihost = $ihost;
}
$this->scheme_normalization();
return true;
}
/**
* Set the port. Returns true on success, false on failure (if there are
* any invalid characters).
*
* @param string $port
* @return bool
*/
protected function set_port($port) {
if ($port === null) {
$this->port = null;
return true;
}
if (strspn($port, '0123456789') === strlen($port)) {
$this->port = (int) $port;
$this->scheme_normalization();
return true;
}
$this->port = null;
return false;
}
/**
* Set the ipath.
*
* @param string $ipath
* @return bool
*/
protected function set_path($ipath) {
static $cache;
if (!$cache) {
$cache = array();
}
$ipath = (string) $ipath;
if (isset($cache[$ipath])) {
$this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
}
else {
$valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
$removed = $this->remove_dot_segments($valid);
$cache[$ipath] = array($valid, $removed);
$this->ipath = ($this->scheme !== null) ? $removed : $valid;
}
$this->scheme_normalization();
return true;
}
/**
* Set the iquery.
*
* @param string $iquery
* @return bool
*/
protected function set_query($iquery) {
if ($iquery === null) {
$this->iquery = null;
}
else {
$this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
$this->scheme_normalization();
}
return true;
}
/**
* Set the ifragment.
*
* @param string $ifragment
* @return bool
*/
protected function set_fragment($ifragment) {
if ($ifragment === null) {
$this->ifragment = null;
}
else {
$this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
$this->scheme_normalization();
}
return true;
}
/**
* Convert an IRI to a URI (or parts thereof)
*
* @param string|bool $iri IRI to convert (or false from {@see \WpOrg\Requests\Iri::get_iri()})
* @return string|false URI if IRI is valid, false otherwise.
*/
protected function to_uri($iri) {
if (!is_string($iri)) {
return false;
}
static $non_ascii;
if (!$non_ascii) {
$non_ascii = implode('', range("\x80", "\xFF"));
}
$position = 0;
$strlen = strlen($iri);
while (($position += strcspn($iri, $non_ascii, $position)) < $strlen) {
$iri = substr_replace($iri, sprintf('%%%02X', ord($iri[$position])), $position, 1);
$position += 3;
$strlen += 2;
}
return $iri;
}
/**
* Get the complete IRI
*
* @return string|false
*/
protected function get_iri() {
if (!$this->is_valid()) {
return false;
}
$iri = '';
if ($this->scheme !== null) {
$iri .= $this->scheme . ':';
}
if (($iauthority = $this->get_iauthority()) !== null) {
$iri .= '//' . $iauthority;
}
$iri .= $this->ipath;
if ($this->iquery !== null) {
$iri .= '?' . $this->iquery;
}
if ($this->ifragment !== null) {
$iri .= '#' . $this->ifragment;
}
return $iri;
}
/**
* Get the complete URI
*
* @return string
*/
protected function get_uri() {
return $this->to_uri($this->get_iri());
}
/**
* Get the complete iauthority
*
* @return string|null
*/
protected function get_iauthority() {
if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) {
return null;
}
$iauthority = '';
if ($this->iuserinfo !== null) {
$iauthority .= $this->iuserinfo . '@';
}
if ($this->ihost !== null) {
$iauthority .= $this->ihost;
}
if ($this->port !== null) {
$iauthority .= ':' . $this->port;
}
return $iauthority;
}
/**
* Get the complete authority
*
* @return string
*/
protected function get_authority() {
$iauthority = $this->get_iauthority();
if (is_string($iauthority)) {
return $this->to_uri($iauthority);
}
else {
return $iauthority;
}
}
}
<?php
/**
* Session handler for persistent requests and default parameters
*
* @package Requests\SessionHandler
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Cookie\Jar;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Iri;
use WpOrg\Requests\Requests;
use WpOrg\Requests\Utility\InputValidator;
/**
* Session handler for persistent requests and default parameters
*
* Allows various options to be set as default values, and merges both the
* options and URL properties together. A base URL can be set for all requests,
* with all subrequests resolved from this. Base options can be set (including
* a shared cookie jar), then overridden for individual requests.
*
* @package Requests\SessionHandler
*/
class Session {
/**
* Base URL for requests
*
* URLs will be made absolute using this as the base
*
* @var string|null
*/
public $url = null;
/**
* Base headers for requests
*
* @var array
*/
public $headers = [];
/**
* Base data for requests
*
* If both the base data and the per-request data are arrays, the data will
* be merged before sending the request.
*
* @var array
*/
public $data = [];
/**
* Base options for requests
*
* The base options are merged with the per-request data for each request.
* The only default option is a shared cookie jar between requests.
*
* Values here can also be set directly via properties on the Session
* object, e.g. `$session->useragent = 'X';`
*
* @var array
*/
public $options = [];
/**
* Create a new session
*
* @param string|Stringable|null $url Base URL for requests
* @param array $headers Default headers for requests
* @param array $data Default data for requests
* @param array $options Default options for requests
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or null.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not an array.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
*/
public function __construct($url = null, $headers = [], $data = [], $options = []) {
if ($url !== null && InputValidator::is_string_or_stringable($url) === false) {
throw InvalidArgument::create(1, '$url', 'string|Stringable|null', gettype($url));
}
if (is_array($headers) === false) {
throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
}
if (is_array($data) === false) {
throw InvalidArgument::create(3, '$data', 'array', gettype($data));
}
if (is_array($options) === false) {
throw InvalidArgument::create(4, '$options', 'array', gettype($options));
}
$this->url = $url;
$this->headers = $headers;
$this->data = $data;
$this->options = $options;
if (empty($this->options['cookies'])) {
$this->options['cookies'] = new Jar();
}
}
/**
* Get a property's value
*
* @param string $name Property name.
* @return mixed|null Property value, null if none found
*/
public function __get($name) {
if (isset($this->options[$name])) {
return $this->options[$name];
}
return null;
}
/**
* Set a property's value
*
* @param string $name Property name.
* @param mixed $value Property value
*/
public function __set($name, $value) {
$this->options[$name] = $value;
}
/**
* Remove a property's value
*
* @param string $name Property name.
*/
public function __isset($name) {
return isset($this->options[$name]);
}
/**
* Remove a property's value
*
* @param string $name Property name.
*/
public function __unset($name) {
unset($this->options[$name]);
}
/**#@+
* @see \WpOrg\Requests\Session::request()
* @param string $url
* @param array $headers
* @param array $options
* @return \WpOrg\Requests\Response
*/
/**
* Send a GET request
*/
public function get($url, $headers = [], $options = []) {
return $this->request($url, $headers, null, Requests::GET, $options);
}
/**
* Send a HEAD request
*/
public function head($url, $headers = [], $options = []) {
return $this->request($url, $headers, null, Requests::HEAD, $options);
}
/**
* Send a DELETE request
*/
public function delete($url, $headers = [], $options = []) {
return $this->request($url, $headers, null, Requests::DELETE, $options);
}
/**#@-*/
/**#@+
* @see \WpOrg\Requests\Session::request()
* @param string $url
* @param array $headers
* @param array $data
* @param array $options
* @return \WpOrg\Requests\Response
*/
/**
* Send a POST request
*/
public function post($url, $headers = [], $data = [], $options = []) {
return $this->request($url, $headers, $data, Requests::POST, $options);
}
/**
* Send a PUT request
*/
public function put($url, $headers = [], $data = [], $options = []) {
return $this->request($url, $headers, $data, Requests::PUT, $options);
}
/**
* Send a PATCH request
*
* Note: Unlike {@see \WpOrg\Requests\Session::post()} and {@see \WpOrg\Requests\Session::put()},
* `$headers` is required, as the specification recommends that should send an ETag
*
* @link https://tools.ietf.org/html/rfc5789
*/
public function patch($url, $headers, $data = [], $options = []) {
return $this->request($url, $headers, $data, Requests::PATCH, $options);
}
/**#@-*/
/**
* Main interface for HTTP requests
*
* This method initiates a request and sends it via a transport before
* parsing.
*
* @see \WpOrg\Requests\Requests::request()
*
* @param string $url URL to request
* @param array $headers Extra headers to send with the request
* @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
* @param string $type HTTP request type (use \WpOrg\Requests\Requests constants)
* @param array $options Options for the request (see {@see \WpOrg\Requests\Requests::request()})
* @return \WpOrg\Requests\Response
*
* @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`)
*/
public function request($url, $headers = [], $data = [], $type = Requests::GET, $options = []) {
$request = $this->merge_request(compact('url', 'headers', 'data', 'options'));
return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']);
}
/**
* Send multiple HTTP requests simultaneously
*
* @see \WpOrg\Requests\Requests::request_multiple()
*
* @param array $requests Requests data (see {@see \WpOrg\Requests\Requests::request_multiple()})
* @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()})
* @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object)
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
*/
public function request_multiple($requests, $options = []) {
if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
}
if (is_array($options) === false) {
throw InvalidArgument::create(2, '$options', 'array', gettype($options));
}
foreach ($requests as $key => $request) {
$requests[$key] = $this->merge_request($request, false);
}
$options = array_merge($this->options, $options);
// Disallow forcing the type, as that's a per request setting
unset($options['type']);
return Requests::request_multiple($requests, $options);
}
public function __wakeup() {
throw new \LogicException( __CLASS__ . ' should never be unserialized' );
}
/**
* Merge a request's data with the default data
*
* @param array $request Request data (same form as {@see \WpOrg\Requests\Session::request_multiple()})
* @param boolean $merge_options Should we merge options as well?
* @return array Request data
*/
protected function merge_request($request, $merge_options = true) {
if ($this->url !== null) {
$request['url'] = Iri::absolutize($this->url, $request['url']);
$request['url'] = $request['url']->uri;
}
if (empty($request['headers'])) {
$request['headers'] = [];
}
$request['headers'] = array_merge($this->headers, $request['headers']);
if (empty($request['data'])) {
if (is_array($this->data)) {
$request['data'] = $this->data;
}
} elseif (is_array($request['data']) && is_array($this->data)) {
$request['data'] = array_merge($this->data, $request['data']);
}
if ($merge_options === true) {
$request['options'] = array_merge($this->options, $request['options']);
// Disallow forcing the type, as that's a per request setting
unset($request['options']['type']);
}
return $request;
}
}
<?php
/**
* Exception based on HTTP response
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\Http\StatusUnknown;
/**
* Exception based on HTTP response
*
* @package Requests\Exceptions
*/
class Http extends Exception {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 0;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Unknown';
/**
* Create a new exception
*
* There is no mechanism to pass in the status code, as this is set by the
* subclass used. Reason phrases can vary, however.
*
* @param string|null $reason Reason phrase
* @param mixed $data Associated data
*/
public function __construct($reason = null, $data = null) {
if ($reason !== null) {
$this->reason = $reason;
}
$message = sprintf('%d %s', $this->code, $this->reason);
parent::__construct($message, 'httpresponse', $data, $this->code);
}
/**
* Get the status message.
*
* @return string
*/
public function getReason() {
return $this->reason;
}
/**
* Get the correct exception class for a given error code
*
* @param int|bool $code HTTP status code, or false if unavailable
* @return string Exception class name to use
*/
public static function get_class($code) {
if (!$code) {
return StatusUnknown::class;
}
$class = sprintf('\WpOrg\Requests\Exception\Http\Status%d', $code);
if (class_exists($class)) {
return $class;
}
return StatusUnknown::class;
}
}
[02-Dec-2025 10:42:24 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/ArgumentCount.php:20
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/ArgumentCount.php on line 20
[02-Dec-2025 10:42:24 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Transport.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Transport.php on line 17
[02-Dec-2025 10:42:24 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http.php:18
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http.php on line 18
[06-Mar-2026 12:45:56 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http.php:18
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http.php on line 18
<?php
namespace WpOrg\Requests\Exception;
use InvalidArgumentException;
/**
* Exception for an invalid argument passed.
*
* @package Requests\Exceptions
* @since 2.0.0
*/
final class InvalidArgument extends InvalidArgumentException {
/**
* Create a new invalid argument exception with a standardized text.
*
* @param int $position The argument position in the function signature. 1-based.
* @param string $name The argument name in the function signature.
* @param string $expected The argument type expected as a string.
* @param string $received The actual argument type received.
*
* @return \WpOrg\Requests\Exception\InvalidArgument
*/
public static function create($position, $name, $expected, $received) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
return new self(
sprintf(
'%s::%s(): Argument #%d (%s) must be of type %s, %s given',
$stack[1]['class'],
$stack[1]['function'],
$position,
$name,
$expected,
$received
)
);
}
}
<?php
/**
* Exception for 402 Payment Required responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 402 Payment Required responses
*
* @package Requests\Exceptions
*/
final class Status402 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 402;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Payment Required';
}
<?php
/**
* Exception for 410 Gone responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 410 Gone responses
*
* @package Requests\Exceptions
*/
final class Status410 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 410;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Gone';
}
<?php
/**
* Exception for 418 I'm A Teapot responses
*
* @link https://tools.ietf.org/html/rfc2324
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 418 I'm A Teapot responses
*
* @link https://tools.ietf.org/html/rfc2324
*
* @package Requests\Exceptions
*/
final class Status418 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 418;
/**
* Reason phrase
*
* @var string
*/
protected $reason = "I'm A Teapot";
}
<?php
/**
* Exception for 428 Precondition Required responses
*
* @link https://tools.ietf.org/html/rfc6585
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 428 Precondition Required responses
*
* @link https://tools.ietf.org/html/rfc6585
*
* @package Requests\Exceptions
*/
final class Status428 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 428;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Precondition Required';
}
<?php
/**
* Exception for 306 Switch Proxy responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 306 Switch Proxy responses
*
* @package Requests\Exceptions
*/
final class Status306 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 306;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Switch Proxy';
}
<?php
/**
* Exception for 414 Request-URI Too Large responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 414 Request-URI Too Large responses
*
* @package Requests\Exceptions
*/
final class Status414 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 414;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Request-URI Too Large';
}
<?php
/**
* Exception for 408 Request Timeout responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 408 Request Timeout responses
*
* @package Requests\Exceptions
*/
final class Status408 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 408;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Request Timeout';
}
<?php
/**
* Exception for 431 Request Header Fields Too Large responses
*
* @link https://tools.ietf.org/html/rfc6585
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 431 Request Header Fields Too Large responses
*
* @link https://tools.ietf.org/html/rfc6585
*
* @package Requests\Exceptions
*/
final class Status431 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 431;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Request Header Fields Too Large';
}
<?php
/**
* Exception for 511 Network Authentication Required responses
*
* @link https://tools.ietf.org/html/rfc6585
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 511 Network Authentication Required responses
*
* @link https://tools.ietf.org/html/rfc6585
*
* @package Requests\Exceptions
*/
final class Status511 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 511;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Network Authentication Required';
}
[03-Jul-2025 12:20:35 America/Bogota] PHP Fatal error: Namespace declaration statement has to be the very first statement or after any declare call in the script in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status417.php on line 9
[02-Dec-2025 10:42:25 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status413.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status413.php on line 17
[02-Dec-2025 10:42:25 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status511.php:21
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status511.php on line 21
[02-Dec-2025 10:42:25 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status408.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status408.php on line 17
[02-Dec-2025 10:42:26 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status402.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status402.php on line 17
[02-Dec-2025 10:42:26 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status417.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status417.php on line 17
[02-Dec-2025 10:42:26 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status405.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status405.php on line 17
[02-Dec-2025 10:42:26 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status412.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status412.php on line 17
[02-Dec-2025 10:42:27 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status429.php:21
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status429.php on line 21
[02-Dec-2025 10:42:27 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status409.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status409.php on line 17
[02-Dec-2025 10:42:27 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status306.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status306.php on line 17
[02-Dec-2025 10:42:27 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status505.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status505.php on line 17
[02-Dec-2025 10:42:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status305.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status305.php on line 17
[02-Dec-2025 10:42:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/StatusUnknown.php:18
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/StatusUnknown.php on line 18
[02-Dec-2025 10:42:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status500.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status500.php on line 17
[02-Dec-2025 10:42:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status407.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status407.php on line 17
[02-Dec-2025 10:42:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status410.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status410.php on line 17
[02-Dec-2025 10:42:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status400.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status400.php on line 17
[02-Dec-2025 10:42:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status416.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status416.php on line 17
[02-Dec-2025 10:42:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status502.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status502.php on line 17
[02-Dec-2025 10:42:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status504.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status504.php on line 17
[02-Dec-2025 10:42:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status304.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status304.php on line 17
[02-Dec-2025 10:42:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status403.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status403.php on line 17
[02-Dec-2025 10:42:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status414.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status414.php on line 17
[02-Dec-2025 10:42:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status428.php:21
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status428.php on line 21
[02-Dec-2025 10:42:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status501.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status501.php on line 17
[02-Dec-2025 10:42:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status503.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status503.php on line 17
[02-Dec-2025 10:42:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status401.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status401.php on line 17
[02-Dec-2025 10:42:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status404.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status404.php on line 17
[02-Dec-2025 10:42:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status411.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status411.php on line 17
[02-Dec-2025 10:42:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status431.php:21
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status431.php on line 21
[02-Dec-2025 10:42:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status415.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status415.php on line 17
[02-Dec-2025 10:42:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status406.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status406.php on line 17
[02-Dec-2025 10:42:33 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Http" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status418.php:21
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Http/Status418.php on line 21
<?php
/**
* Exception for 412 Precondition Failed responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 412 Precondition Failed responses
*
* @package Requests\Exceptions
*/
final class Status412 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 412;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Precondition Failed';
}
<?php
/**
* Exception for 411 Length Required responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 411 Length Required responses
*
* @package Requests\Exceptions
*/
final class Status411 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 411;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Length Required';
}
<?php
/**
* Exception for 417 Expectation Failed responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 417 Expectation Failed responses
*
* @package Requests\Exceptions
*/
final class Status417 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 417;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Expectation Failed';
}
<?php
/**
* Exception for 500 Internal Server Error responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 500 Internal Server Error responses
*
* @package Requests\Exceptions
*/
final class Status500 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 500;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Internal Server Error';
}
<?php
/**
* Exception for 406 Not Acceptable responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 406 Not Acceptable responses
*
* @package Requests\Exceptions
*/
final class Status406 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 406;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Not Acceptable';
}
<?php
/**
* Exception for 403 Forbidden responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 403 Forbidden responses
*
* @package Requests\Exceptions
*/
final class Status403 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 403;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Forbidden';
}
<?php
/**
* Exception for 502 Bad Gateway responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 502 Bad Gateway responses
*
* @package Requests\Exceptions
*/
final class Status502 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 502;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Bad Gateway';
}
<?php
/**
* Exception for 413 Request Entity Too Large responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 413 Request Entity Too Large responses
*
* @package Requests\Exceptions
*/
final class Status413 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 413;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Request Entity Too Large';
}
<?php
/**
* Exception for 400 Bad Request responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 400 Bad Request responses
*
* @package Requests\Exceptions
*/
final class Status400 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 400;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Bad Request';
}
<?php
/**
* Exception for 404 Not Found responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 404 Not Found responses
*
* @package Requests\Exceptions
*/
final class Status404 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 404;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Not Found';
}
<?php
/**
* Exception for 429 Too Many Requests responses
*
* @link https://tools.ietf.org/html/draft-nottingham-http-new-status-04
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 429 Too Many Requests responses
*
* @link https://tools.ietf.org/html/draft-nottingham-http-new-status-04
*
* @package Requests\Exceptions
*/
final class Status429 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 429;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Too Many Requests';
}
<?php
/**
* Exception for 305 Use Proxy responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 305 Use Proxy responses
*
* @package Requests\Exceptions
*/
final class Status305 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 305;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Use Proxy';
}
<?php
/**
* Exception for 304 Not Modified responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 304 Not Modified responses
*
* @package Requests\Exceptions
*/
final class Status304 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 304;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Not Modified';
}
<?php
/**
* Exception for 409 Conflict responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 409 Conflict responses
*
* @package Requests\Exceptions
*/
final class Status409 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 409;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Conflict';
}
<?php
/**
* Exception for 504 Gateway Timeout responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 504 Gateway Timeout responses
*
* @package Requests\Exceptions
*/
final class Status504 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 504;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Gateway Timeout';
}
<?php
/**
* Exception for 501 Not Implemented responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 501 Not Implemented responses
*
* @package Requests\Exceptions
*/
final class Status501 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 501;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Not Implemented';
}
<?php
/**
* Exception for 415 Unsupported Media Type responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 415 Unsupported Media Type responses
*
* @package Requests\Exceptions
*/
final class Status415 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 415;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Unsupported Media Type';
}
<?php
/**
* Exception for 407 Proxy Authentication Required responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 407 Proxy Authentication Required responses
*
* @package Requests\Exceptions
*/
final class Status407 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 407;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Proxy Authentication Required';
}
<?php
/**
* Exception for 401 Unauthorized responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 401 Unauthorized responses
*
* @package Requests\Exceptions
*/
final class Status401 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 401;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Unauthorized';
}
<?php
/**
* Exception for 416 Requested Range Not Satisfiable responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 416 Requested Range Not Satisfiable responses
*
* @package Requests\Exceptions
*/
final class Status416 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 416;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Requested Range Not Satisfiable';
}
<?php
/**
* Exception for unknown status responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Response;
/**
* Exception for unknown status responses
*
* @package Requests\Exceptions
*/
final class StatusUnknown extends Http {
/**
* HTTP status code
*
* @var integer|bool Code if available, false if an error occurred
*/
protected $code = 0;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Unknown';
/**
* Create a new exception
*
* If `$data` is an instance of {@see \WpOrg\Requests\Response}, uses the status
* code from it. Otherwise, sets as 0
*
* @param string|null $reason Reason phrase
* @param mixed $data Associated data
*/
public function __construct($reason = null, $data = null) {
if ($data instanceof Response) {
$this->code = (int) $data->status_code;
}
parent::__construct($reason, $data);
}
}
<?php
/**
* Exception for 503 Service Unavailable responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 503 Service Unavailable responses
*
* @package Requests\Exceptions
*/
final class Status503 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 503;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Service Unavailable';
}
<?php
/**
* Exception for 405 Method Not Allowed responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 405 Method Not Allowed responses
*
* @package Requests\Exceptions
*/
final class Status405 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 405;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'Method Not Allowed';
}
<?php
/**
* Exception for 505 HTTP Version Not Supported responses
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Exception\Http;
/**
* Exception for 505 HTTP Version Not Supported responses
*
* @package Requests\Exceptions
*/
final class Status505 extends Http {
/**
* HTTP status code
*
* @var integer
*/
protected $code = 505;
/**
* Reason phrase
*
* @var string
*/
protected $reason = 'HTTP Version Not Supported';
}
<?php
namespace WpOrg\Requests\Exception;
use WpOrg\Requests\Exception;
/**
* Exception for when an incorrect number of arguments are passed to a method.
*
* Typically, this exception is used when all arguments for a method are optional,
* but certain arguments need to be passed together, i.e. a method which can be called
* with no arguments or with two arguments, but not with one argument.
*
* Along the same lines, this exception is also used if a method expects an array
* with a certain number of elements and the provided number of elements does not comply.
*
* @package Requests\Exceptions
* @since 2.0.0
*/
final class ArgumentCount extends Exception {
/**
* Create a new argument count exception with a standardized text.
*
* @param string $expected The argument count expected as a phrase.
* For example: `at least 2 arguments` or `exactly 1 argument`.
* @param int $received The actual argument count received.
* @param string $type Exception type.
*
* @return \WpOrg\Requests\Exception\ArgumentCount
*/
public static function create($expected, $received, $type) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
return new self(
sprintf(
'%s::%s() expects %s, %d given',
$stack[1]['class'],
$stack[1]['function'],
$expected,
$received
),
$type
);
}
}
[02-Dec-2025 10:42:33 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Exception\Transport" not found in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Transport/Curl.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Exception/Transport/Curl.php on line 17
<?php
/**
* CURL Transport Exception.
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception\Transport;
use WpOrg\Requests\Exception\Transport;
/**
* CURL Transport Exception.
*
* @package Requests\Exceptions
*/
final class Curl extends Transport {
const EASY = 'cURLEasy';
const MULTI = 'cURLMulti';
const SHARE = 'cURLShare';
/**
* cURL error code
*
* @var integer
*/
protected $code = -1;
/**
* Which type of cURL error
*
* EASY|MULTI|SHARE
*
* @var string
*/
protected $type = 'Unknown';
/**
* Clear text error message
*
* @var string
*/
protected $reason = 'Unknown';
/**
* Create a new exception.
*
* @param string $message Exception message.
* @param string $type Exception type.
* @param mixed $data Associated data, if applicable.
* @param int $code Exception numerical code, if applicable.
*/
public function __construct($message, $type, $data = null, $code = 0) {
if ($type !== null) {
$this->type = $type;
}
if ($code !== null) {
$this->code = (int) $code;
}
if ($message !== null) {
$this->reason = $message;
}
$message = sprintf('%d %s', $this->code, $this->reason);
parent::__construct($message, $this->type, $data, $this->code);
}
/**
* Get the error message.
*
* @return string
*/
public function getReason() {
return $this->reason;
}
}
<?php
/**
* Transport Exception
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests\Exception;
use WpOrg\Requests\Exception;
/**
* Transport Exception
*
* @package Requests\Exceptions
*/
class Transport extends Exception {}
<?php
/**
* Cookie storage object
*
* @package Requests\Cookies
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Iri;
use WpOrg\Requests\Response\Headers;
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
use WpOrg\Requests\Utility\InputValidator;
/**
* Cookie storage object
*
* @package Requests\Cookies
*/
class Cookie {
/**
* Cookie name.
*
* @var string
*/
public $name;
/**
* Cookie value.
*
* @var string
*/
public $value;
/**
* Cookie attributes
*
* Valid keys are `'path'`, `'domain'`, `'expires'`, `'max-age'`, `'secure'` and
* `'httponly'`.
*
* @var \WpOrg\Requests\Utility\CaseInsensitiveDictionary|array Array-like object
*/
public $attributes = [];
/**
* Cookie flags
*
* Valid keys are `'creation'`, `'last-access'`, `'persistent'` and `'host-only'`.
*
* @var array
*/
public $flags = [];
/**
* Reference time for relative calculations
*
* This is used in place of `time()` when calculating Max-Age expiration and
* checking time validity.
*
* @var int
*/
public $reference_time = 0;
/**
* Create a new cookie object
*
* @param string $name The name of the cookie.
* @param string $value The value for the cookie.
* @param array|\WpOrg\Requests\Utility\CaseInsensitiveDictionary $attributes Associative array of attribute data
* @param array $flags The flags for the cookie.
* Valid keys are `'creation'`, `'last-access'`,
* `'persistent'` and `'host-only'`.
* @param int|null $reference_time Reference time for relative calculations.
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $name argument is not a string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $value argument is not a string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $attributes argument is not an array or iterable object with array access.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $flags argument is not an array.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $reference_time argument is not an integer or null.
*/
public function __construct($name, $value, $attributes = [], $flags = [], $reference_time = null) {
if (is_string($name) === false) {
throw InvalidArgument::create(1, '$name', 'string', gettype($name));
}
if (is_string($value) === false) {
throw InvalidArgument::create(2, '$value', 'string', gettype($value));
}
if (InputValidator::has_array_access($attributes) === false || InputValidator::is_iterable($attributes) === false) {
throw InvalidArgument::create(3, '$attributes', 'array|ArrayAccess&Traversable', gettype($attributes));
}
if (is_array($flags) === false) {
throw InvalidArgument::create(4, '$flags', 'array', gettype($flags));
}
if ($reference_time !== null && is_int($reference_time) === false) {
throw InvalidArgument::create(5, '$reference_time', 'integer|null', gettype($reference_time));
}
$this->name = $name;
$this->value = $value;
$this->attributes = $attributes;
$default_flags = [
'creation' => time(),
'last-access' => time(),
'persistent' => false,
'host-only' => true,
];
$this->flags = array_merge($default_flags, $flags);
$this->reference_time = time();
if ($reference_time !== null) {
$this->reference_time = $reference_time;
}
$this->normalize();
}
/**
* Get the cookie value
*
* Attributes and other data can be accessed via methods.
*/
public function __toString() {
return $this->value;
}
/**
* Check if a cookie is expired.
*
* Checks the age against $this->reference_time to determine if the cookie
* is expired.
*
* @return boolean True if expired, false if time is valid.
*/
public function is_expired() {
// RFC6265, s. 4.1.2.2:
// If a cookie has both the Max-Age and the Expires attribute, the Max-
// Age attribute has precedence and controls the expiration date of the
// cookie.
if (isset($this->attributes['max-age'])) {
$max_age = $this->attributes['max-age'];
return $max_age < $this->reference_time;
}
if (isset($this->attributes['expires'])) {
$expires = $this->attributes['expires'];
return $expires < $this->reference_time;
}
return false;
}
/**
* Check if a cookie is valid for a given URI
*
* @param \WpOrg\Requests\Iri $uri URI to check
* @return boolean Whether the cookie is valid for the given URI
*/
public function uri_matches(Iri $uri) {
if (!$this->domain_matches($uri->host)) {
return false;
}
if (!$this->path_matches($uri->path)) {
return false;
}
return empty($this->attributes['secure']) || $uri->scheme === 'https';
}
/**
* Check if a cookie is valid for a given domain
*
* @param string $domain Domain to check
* @return boolean Whether the cookie is valid for the given domain
*/
public function domain_matches($domain) {
if (is_string($domain) === false) {
return false;
}
if (!isset($this->attributes['domain'])) {
// Cookies created manually; cookies created by Requests will set
// the domain to the requested domain
return true;
}
$cookie_domain = $this->attributes['domain'];
if ($cookie_domain === $domain) {
// The cookie domain and the passed domain are identical.
return true;
}
// If the cookie is marked as host-only and we don't have an exact
// match, reject the cookie
if ($this->flags['host-only'] === true) {
return false;
}
if (strlen($domain) <= strlen($cookie_domain)) {
// For obvious reasons, the cookie domain cannot be a suffix if the passed domain
// is shorter than the cookie domain
return false;
}
if (substr($domain, -1 * strlen($cookie_domain)) !== $cookie_domain) {
// The cookie domain should be a suffix of the passed domain.
return false;
}
$prefix = substr($domain, 0, strlen($domain) - strlen($cookie_domain));
if (substr($prefix, -1) !== '.') {
// The last character of the passed domain that is not included in the
// domain string should be a %x2E (".") character.
return false;
}
// The passed domain should be a host name (i.e., not an IP address).
return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $domain);
}
/**
* Check if a cookie is valid for a given path
*
* From the path-match check in RFC 6265 section 5.1.4
*
* @param string $request_path Path to check
* @return boolean Whether the cookie is valid for the given path
*/
public function path_matches($request_path) {
if (empty($request_path)) {
// Normalize empty path to root
$request_path = '/';
}
if (!isset($this->attributes['path'])) {
// Cookies created manually; cookies created by Requests will set
// the path to the requested path
return true;
}
if (is_scalar($request_path) === false) {
return false;
}
$cookie_path = $this->attributes['path'];
if ($cookie_path === $request_path) {
// The cookie-path and the request-path are identical.
return true;
}
if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) {
if (substr($cookie_path, -1) === '/') {
// The cookie-path is a prefix of the request-path, and the last
// character of the cookie-path is %x2F ("/").
return true;
}
if (substr($request_path, strlen($cookie_path), 1) === '/') {
// The cookie-path is a prefix of the request-path, and the
// first character of the request-path that is not included in
// the cookie-path is a %x2F ("/") character.
return true;
}
}
return false;
}
/**
* Normalize cookie and attributes
*
* @return boolean Whether the cookie was successfully normalized
*/
public function normalize() {
foreach ($this->attributes as $key => $value) {
$orig_value = $value;
if (is_string($key)) {
$value = $this->normalize_attribute($key, $value);
}
if ($value === null) {
unset($this->attributes[$key]);
continue;
}
if ($value !== $orig_value) {
$this->attributes[$key] = $value;
}
}
return true;
}
/**
* Parse an individual cookie attribute
*
* Handles parsing individual attributes from the cookie values.
*
* @param string $name Attribute name
* @param string|int|bool $value Attribute value (string/integer value, or true if empty/flag)
* @return mixed Value if available, or null if the attribute value is invalid (and should be skipped)
*/
protected function normalize_attribute($name, $value) {
switch (strtolower($name)) {
case 'expires':
// Expiration parsing, as per RFC 6265 section 5.2.1
if (is_int($value)) {
return $value;
}
$expiry_time = strtotime($value);
if ($expiry_time === false) {
return null;
}
return $expiry_time;
case 'max-age':
// Expiration parsing, as per RFC 6265 section 5.2.2
if (is_int($value)) {
return $value;
}
// Check that we have a valid age
if (!preg_match('/^-?\d+$/', $value)) {
return null;
}
$delta_seconds = (int) $value;
if ($delta_seconds <= 0) {
$expiry_time = 0;
} else {
$expiry_time = $this->reference_time + $delta_seconds;
}
return $expiry_time;
case 'domain':
// Domains are not required as per RFC 6265 section 5.2.3
if (empty($value)) {
return null;
}
// Domain normalization, as per RFC 6265 section 5.2.3
if ($value[0] === '.') {
$value = substr($value, 1);
}
return $value;
default:
return $value;
}
}
/**
* Format a cookie for a Cookie header
*
* This is used when sending cookies to a server.
*
* @return string Cookie formatted for Cookie header
*/
public function format_for_header() {
return sprintf('%s=%s', $this->name, $this->value);
}
/**
* Format a cookie for a Set-Cookie header
*
* This is used when sending cookies to clients. This isn't really
* applicable to client-side usage, but might be handy for debugging.
*
* @return string Cookie formatted for Set-Cookie header
*/
public function format_for_set_cookie() {
$header_value = $this->format_for_header();
if (!empty($this->attributes)) {
$parts = [];
foreach ($this->attributes as $key => $value) {
// Ignore non-associative attributes
if (is_numeric($key)) {
$parts[] = $value;
} else {
$parts[] = sprintf('%s=%s', $key, $value);
}
}
$header_value .= '; ' . implode('; ', $parts);
}
return $header_value;
}
/**
* Parse a cookie string into a cookie object
*
* Based on Mozilla's parsing code in Firefox and related projects, which
* is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265
* specifies some of this handling, but not in a thorough manner.
*
* @param string $cookie_header Cookie header value (from a Set-Cookie header)
* @param string $name
* @param int|null $reference_time
* @return \WpOrg\Requests\Cookie Parsed cookie object
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cookie_header argument is not a string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $name argument is not a string.
*/
public static function parse($cookie_header, $name = '', $reference_time = null) {
if (is_string($cookie_header) === false) {
throw InvalidArgument::create(1, '$cookie_header', 'string', gettype($cookie_header));
}
if (is_string($name) === false) {
throw InvalidArgument::create(2, '$name', 'string', gettype($name));
}
$parts = explode(';', $cookie_header);
$kvparts = array_shift($parts);
if (!empty($name)) {
$value = $cookie_header;
} elseif (strpos($kvparts, '=') === false) {
// Some sites might only have a value without the equals separator.
// Deviate from RFC 6265 and pretend it was actually a blank name
// (`=foo`)
//
// https://bugzilla.mozilla.org/show_bug.cgi?id=169091
$name = '';
$value = $kvparts;
} else {
list($name, $value) = explode('=', $kvparts, 2);
}
$name = trim($name);
$value = trim($value);
// Attribute keys are handled case-insensitively
$attributes = new CaseInsensitiveDictionary();
if (!empty($parts)) {
foreach ($parts as $part) {
if (strpos($part, '=') === false) {
$part_key = $part;
$part_value = true;
} else {
list($part_key, $part_value) = explode('=', $part, 2);
$part_value = trim($part_value);
}
$part_key = trim($part_key);
$attributes[$part_key] = $part_value;
}
}
return new static($name, $value, $attributes, [], $reference_time);
}
/**
* Parse all Set-Cookie headers from request headers
*
* @param \WpOrg\Requests\Response\Headers $headers Headers to parse from
* @param \WpOrg\Requests\Iri|null $origin URI for comparing cookie origins
* @param int|null $time Reference time for expiration calculation
* @return array
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $origin argument is not null or an instance of the Iri class.
*/
public static function parse_from_headers(Headers $headers, $origin = null, $time = null) {
$cookie_headers = $headers->getValues('Set-Cookie');
if (empty($cookie_headers)) {
return [];
}
if ($origin !== null && !($origin instanceof Iri)) {
throw InvalidArgument::create(2, '$origin', Iri::class . ' or null', gettype($origin));
}
$cookies = [];
foreach ($cookie_headers as $header) {
$parsed = self::parse($header, '', $time);
// Default domain/path attributes
if (empty($parsed->attributes['domain']) && !empty($origin)) {
$parsed->attributes['domain'] = $origin->host;
$parsed->flags['host-only'] = true;
} else {
$parsed->flags['host-only'] = false;
}
$path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/');
if (!$path_is_valid && !empty($origin)) {
$path = $origin->path;
// Default path normalization as per RFC 6265 section 5.1.4
if (substr($path, 0, 1) !== '/') {
// If the uri-path is empty or if the first character of
// the uri-path is not a %x2F ("/") character, output
// %x2F ("/") and skip the remaining steps.
$path = '/';
} elseif (substr_count($path, '/') === 1) {
// If the uri-path contains no more than one %x2F ("/")
// character, output %x2F ("/") and skip the remaining
// step.
$path = '/';
} else {
// Output the characters of the uri-path from the first
// character up to, but not including, the right-most
// %x2F ("/").
$path = substr($path, 0, strrpos($path, '/'));
}
$parsed->attributes['path'] = $path;
}
// Reject invalid cookie domains
if (!empty($origin) && !$parsed->domain_matches($origin->host)) {
continue;
}
$cookies[$parsed->name] = $parsed;
}
return $cookies;
}
}
[02-Dec-2025 10:42:16 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\HookManager" not found in /home/coopserp/public_html/wp-includes/Requests/src/Hooks.php:19
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Hooks.php on line 19
[05-Jan-2026 03:37:28 America/Bogota] PHP Fatal error: Namespace declaration statement has to be the very first statement or after any declare call in the script in /home/coopserp/public_html/wp-includes/Requests/src/Hooks.php on line 9
[06-Mar-2026 12:32:10 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\HookManager" not found in /home/coopserp/public_html/wp-includes/Requests/src/Hooks.php:19
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Hooks.php on line 19
<?php
/**
* Proxy connection interface
*
* @package Requests\Proxy
* @since 1.6
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Hooks;
/**
* Proxy connection interface
*
* Implement this interface to handle proxy settings and authentication
*
* Parameters should be passed via the constructor where possible, as this
* makes it much easier for users to use your provider.
*
* @see \WpOrg\Requests\Hooks
*
* @package Requests\Proxy
* @since 1.6
*/
interface Proxy {
/**
* Register hooks as needed
*
* This method is called in {@see \WpOrg\Requests\Requests::request()} when the user
* has set an instance as the 'auth' option. Use this callback to register all the
* hooks you'll need.
*
* @see \WpOrg\Requests\Hooks::register()
* @param \WpOrg\Requests\Hooks $hooks Hook system
*/
public function register(Hooks $hooks);
}
<?php
/**
* Class to validate and to work with IPv6 addresses
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;
/**
* Class to validate and to work with IPv6 addresses
*
* This was originally based on the PEAR class of the same name, but has been
* entirely rewritten.
*
* @package Requests\Utilities
*/
final class Ipv6 {
/**
* Uncompresses an IPv6 address
*
* RFC 4291 allows you to compress consecutive zero pieces in an address to
* '::'. This method expects a valid IPv6 address and expands the '::' to
* the required number of zero pieces.
*
* Example: FF01::101 -> FF01:0:0:0:0:0:0:101
* ::1 -> 0:0:0:0:0:0:0:1
*
* @author Alexander Merz <alexander.merz@web.de>
* @author elfrink at introweb dot nl
* @author Josh Peck <jmp at joshpeck dot org>
* @copyright 2003-2005 The PHP Group
* @license https://opensource.org/licenses/bsd-license.php
*
* @param string|Stringable $ip An IPv6 address
* @return string The uncompressed IPv6 address
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
*/
public static function uncompress($ip) {
if (InputValidator::is_string_or_stringable($ip) === false) {
throw InvalidArgument::create(1, '$ip', 'string|Stringable', gettype($ip));
}
$ip = (string) $ip;
if (substr_count($ip, '::') !== 1) {
return $ip;
}
list($ip1, $ip2) = explode('::', $ip);
$c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':');
$c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':');
if (strpos($ip2, '.') !== false) {
$c2++;
}
if ($c1 === -1 && $c2 === -1) {
// ::
$ip = '0:0:0:0:0:0:0:0';
} elseif ($c1 === -1) {
// ::xxx
$fill = str_repeat('0:', 7 - $c2);
$ip = str_replace('::', $fill, $ip);
} elseif ($c2 === -1) {
// xxx::
$fill = str_repeat(':0', 7 - $c1);
$ip = str_replace('::', $fill, $ip);
} else {
// xxx::xxx
$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
$ip = str_replace('::', $fill, $ip);
}
return $ip;
}
/**
* Compresses an IPv6 address
*
* RFC 4291 allows you to compress consecutive zero pieces in an address to
* '::'. This method expects a valid IPv6 address and compresses consecutive
* zero pieces to '::'.
*
* Example: FF01:0:0:0:0:0:0:101 -> FF01::101
* 0:0:0:0:0:0:0:1 -> ::1
*
* @see \WpOrg\Requests\Ipv6::uncompress()
*
* @param string $ip An IPv6 address
* @return string The compressed IPv6 address
*/
public static function compress($ip) {
// Prepare the IP to be compressed.
// Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
$ip = self::uncompress($ip);
$ip_parts = self::split_v6_v4($ip);
// Replace all leading zeros
$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
// Find bunches of zeros
if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
$max = 0;
$pos = null;
foreach ($matches[0] as $match) {
if (strlen($match[0]) > $max) {
$max = strlen($match[0]);
$pos = $match[1];
}
}
$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
}
if ($ip_parts[1] !== '') {
return implode(':', $ip_parts);
} else {
return $ip_parts[0];
}
}
/**
* Splits an IPv6 address into the IPv6 and IPv4 representation parts
*
* RFC 4291 allows you to represent the last two parts of an IPv6 address
* using the standard IPv4 representation
*
* Example: 0:0:0:0:0:0:13.1.68.3
* 0:0:0:0:0:FFFF:129.144.52.38
*
* @param string $ip An IPv6 address
* @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
*/
private static function split_v6_v4($ip) {
if (strpos($ip, '.') !== false) {
$pos = strrpos($ip, ':');
$ipv6_part = substr($ip, 0, $pos);
$ipv4_part = substr($ip, $pos + 1);
return [$ipv6_part, $ipv4_part];
} else {
return [$ip, ''];
}
}
/**
* Checks an IPv6 address
*
* Checks if the given IP is a valid IPv6 address
*
* @param string $ip An IPv6 address
* @return bool true if $ip is a valid IPv6 address
*/
public static function check_ipv6($ip) {
// Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
$ip = self::uncompress($ip);
list($ipv6, $ipv4) = self::split_v6_v4($ip);
$ipv6 = explode(':', $ipv6);
$ipv4 = explode('.', $ipv4);
if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
foreach ($ipv6 as $ipv6_part) {
// The section can't be empty
if ($ipv6_part === '') {
return false;
}
// Nor can it be over four characters
if (strlen($ipv6_part) > 4) {
return false;
}
// Remove leading zeros (this is safe because of the above)
$ipv6_part = ltrim($ipv6_part, '0');
if ($ipv6_part === '') {
$ipv6_part = '0';
}
// Check the value is valid
$value = hexdec($ipv6_part);
if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
return false;
}
}
if (count($ipv4) === 4) {
foreach ($ipv4 as $ipv4_part) {
$value = (int) $ipv4_part;
if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
return false;
}
}
}
return true;
} else {
return false;
}
}
}
<?php
/**
* Authentication provider interface
*
* @package Requests\Authentication
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Hooks;
/**
* Authentication provider interface
*
* Implement this interface to act as an authentication provider.
*
* Parameters should be passed via the constructor where possible, as this
* makes it much easier for users to use your provider.
*
* @see \WpOrg\Requests\Hooks
*
* @package Requests\Authentication
*/
interface Auth {
/**
* Register hooks as needed
*
* This method is called in {@see \WpOrg\Requests\Requests::request()} when the user
* has set an instance as the 'auth' option. Use this callback to register all the
* hooks you'll need.
*
* @see \WpOrg\Requests\Hooks::register()
* @param \WpOrg\Requests\Hooks $hooks Hook system
*/
public function register(Hooks $hooks);
}
<?php
/**
* Exception for HTTP requests
*
* @package Requests\Exceptions
*/
namespace WpOrg\Requests;
use Exception as PHPException;
/**
* Exception for HTTP requests
*
* @package Requests\Exceptions
*/
class Exception extends PHPException {
/**
* Type of exception
*
* @var string
*/
protected $type;
/**
* Data associated with the exception
*
* @var mixed
*/
protected $data;
/**
* Create a new exception
*
* @param string $message Exception message
* @param string $type Exception type
* @param mixed $data Associated data
* @param integer $code Exception numerical code, if applicable
*/
public function __construct($message, $type, $data = null, $code = 0) {
parent::__construct($message, $code);
$this->type = $type;
$this->data = $data;
}
/**
* Like {@see \Exception::getCode()}, but a string code.
*
* @codeCoverageIgnore
* @return string
*/
public function getType() {
return $this->type;
}
/**
* Gives any relevant data
*
* @codeCoverageIgnore
* @return mixed
*/
public function getData() {
return $this->data;
}
}
<?php
/**
* Port utilities for Requests
*
* @package Requests\Utilities
* @since 2.0.0
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
/**
* Find the correct port depending on the Request type.
*
* @package Requests\Utilities
* @since 2.0.0
*/
final class Port {
/**
* Port to use with Acap requests.
*
* @var int
*/
const ACAP = 674;
/**
* Port to use with Dictionary requests.
*
* @var int
*/
const DICT = 2628;
/**
* Port to use with HTTP requests.
*
* @var int
*/
const HTTP = 80;
/**
* Port to use with HTTP over SSL requests.
*
* @var int
*/
const HTTPS = 443;
/**
* Retrieve the port number to use.
*
* @param string $type Request type.
* The following requests types are supported:
* 'acap', 'dict', 'http' and 'https'.
*
* @return int
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When a non-string input has been passed.
* @throws \WpOrg\Requests\Exception When a non-supported port is requested ('portnotsupported').
*/
public static function get($type) {
if (!is_string($type)) {
throw InvalidArgument::create(1, '$type', 'string', gettype($type));
}
$type = strtoupper($type);
if (!defined("self::{$type}")) {
$message = sprintf('Invalid port type (%s) passed', $type);
throw new Exception($message, 'portnotsupported');
}
return constant("self::{$type}");
}
}
[02-Dec-2025 10:42:21 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\Auth" not found in /home/coopserp/public_html/wp-includes/Requests/src/Auth/Basic.php:23
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Auth/Basic.php on line 23
<?php
/**
* Basic Authentication provider
*
* @package Requests\Authentication
*/
namespace WpOrg\Requests\Auth;
use WpOrg\Requests\Auth;
use WpOrg\Requests\Exception\ArgumentCount;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Hooks;
/**
* Basic Authentication provider
*
* Provides a handler for Basic HTTP authentication via the Authorization
* header.
*
* @package Requests\Authentication
*/
class Basic implements Auth {
/**
* Username
*
* @var string
*/
public $user;
/**
* Password
*
* @var string
*/
public $pass;
/**
* Constructor
*
* @since 2.0 Throws an `InvalidArgument` exception.
* @since 2.0 Throws an `ArgumentCount` exception instead of the Requests base `Exception.
*
* @param array|null $args Array of user and password. Must have exactly two elements
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array or null.
* @throws \WpOrg\Requests\Exception\ArgumentCount On incorrect number of array elements (`authbasicbadargs`).
*/
public function __construct($args = null) {
if (is_array($args)) {
if (count($args) !== 2) {
throw ArgumentCount::create('an array with exactly two elements', count($args), 'authbasicbadargs');
}
list($this->user, $this->pass) = $args;
return;
}
if ($args !== null) {
throw InvalidArgument::create(1, '$args', 'array|null', gettype($args));
}
}
/**
* Register the necessary callbacks
*
* @see \WpOrg\Requests\Auth\Basic::curl_before_send()
* @see \WpOrg\Requests\Auth\Basic::fsockopen_header()
* @param \WpOrg\Requests\Hooks $hooks Hook system
*/
public function register(Hooks $hooks) {
$hooks->register('curl.before_send', [$this, 'curl_before_send']);
$hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']);
}
/**
* Set cURL parameters before the data is sent
*
* @param resource|\CurlHandle $handle cURL handle
*/
public function curl_before_send(&$handle) {
curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString());
}
/**
* Add extra headers to the request before sending
*
* @param string $out HTTP header string
*/
public function fsockopen_header(&$out) {
$out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString()));
}
/**
* Get the authentication string (user:pass)
*
* @return string
*/
public function getAuthString() {
return $this->user . ':' . $this->pass;
}
}
<?php
/**
* Requests for PHP
*
* Inspired by Requests for Python.
*
* Based on concepts from SimplePie_File, RequestCore and WP_Http.
*
* @package Requests
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Auth\Basic;
use WpOrg\Requests\Capability;
use WpOrg\Requests\Cookie\Jar;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Hooks;
use WpOrg\Requests\IdnaEncoder;
use WpOrg\Requests\Iri;
use WpOrg\Requests\Proxy\Http;
use WpOrg\Requests\Response;
use WpOrg\Requests\Transport\Curl;
use WpOrg\Requests\Transport\Fsockopen;
use WpOrg\Requests\Utility\InputValidator;
/**
* Requests for PHP
*
* Inspired by Requests for Python.
*
* Based on concepts from SimplePie_File, RequestCore and WP_Http.
*
* @package Requests
*/
class Requests {
/**
* POST method
*
* @var string
*/
const POST = 'POST';
/**
* PUT method
*
* @var string
*/
const PUT = 'PUT';
/**
* GET method
*
* @var string
*/
const GET = 'GET';
/**
* HEAD method
*
* @var string
*/
const HEAD = 'HEAD';
/**
* DELETE method
*
* @var string
*/
const DELETE = 'DELETE';
/**
* OPTIONS method
*
* @var string
*/
const OPTIONS = 'OPTIONS';
/**
* TRACE method
*
* @var string
*/
const TRACE = 'TRACE';
/**
* PATCH method
*
* @link https://tools.ietf.org/html/rfc5789
* @var string
*/
const PATCH = 'PATCH';
/**
* Default size of buffer size to read streams
*
* @var integer
*/
const BUFFER_SIZE = 1160;
/**
* Option defaults.
*
* @see \WpOrg\Requests\Requests::get_default_options()
* @see \WpOrg\Requests\Requests::request() for values returned by this method
*
* @since 2.0.0
*
* @var array
*/
const OPTION_DEFAULTS = [
'timeout' => 10,
'connect_timeout' => 10,
'useragent' => 'php-requests/' . self::VERSION,
'protocol_version' => 1.1,
'redirected' => 0,
'redirects' => 10,
'follow_redirects' => true,
'blocking' => true,
'type' => self::GET,
'filename' => false,
'auth' => false,
'proxy' => false,
'cookies' => false,
'max_bytes' => false,
'idn' => true,
'hooks' => null,
'transport' => null,
'verify' => null,
'verifyname' => true,
];
/**
* Default supported Transport classes.
*
* @since 2.0.0
*
* @var array
*/
const DEFAULT_TRANSPORTS = [
Curl::class => Curl::class,
Fsockopen::class => Fsockopen::class,
];
/**
* Current version of Requests
*
* @var string
*/
const VERSION = '2.0.11';
/**
* Selected transport name
*
* Use {@see \WpOrg\Requests\Requests::get_transport()} instead
*
* @var array
*/
public static $transport = [];
/**
* Registered transport classes
*
* @var array
*/
protected static $transports = [];
/**
* Default certificate path.
*
* @see \WpOrg\Requests\Requests::get_certificate_path()
* @see \WpOrg\Requests\Requests::set_certificate_path()
*
* @var string
*/
protected static $certificate_path = __DIR__ . '/../certificates/cacert.pem';
/**
* All (known) valid deflate, gzip header magic markers.
*
* These markers relate to different compression levels.
*
* @link https://stackoverflow.com/a/43170354/482864 Marker source.
*
* @since 2.0.0
*
* @var array
*/
private static $magic_compression_headers = [
"\x1f\x8b" => true, // Gzip marker.
"\x78\x01" => true, // Zlib marker - level 1.
"\x78\x5e" => true, // Zlib marker - level 2 to 5.
"\x78\x9c" => true, // Zlib marker - level 6.
"\x78\xda" => true, // Zlib marker - level 7 to 9.
];
/**
* This is a static class, do not instantiate it
*
* @codeCoverageIgnore
*/
private function __construct() {}
/**
* Register a transport
*
* @param string $transport Transport class to add, must support the \WpOrg\Requests\Transport interface
*/
public static function add_transport($transport) {
if (empty(self::$transports)) {
self::$transports = self::DEFAULT_TRANSPORTS;
}
self::$transports[$transport] = $transport;
}
/**
* Get the fully qualified class name (FQCN) for a working transport.
*
* @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
* @return string FQCN of the transport to use, or an empty string if no transport was
* found which provided the requested capabilities.
*/
protected static function get_transport_class(array $capabilities = []) {
// Caching code, don't bother testing coverage.
// @codeCoverageIgnoreStart
// Array of capabilities as a string to be used as an array key.
ksort($capabilities);
$cap_string = serialize($capabilities);
// Don't search for a transport if it's already been done for these $capabilities.
if (isset(self::$transport[$cap_string])) {
return self::$transport[$cap_string];
}
// Ensure we will not run this same check again later on.
self::$transport[$cap_string] = '';
// @codeCoverageIgnoreEnd
if (empty(self::$transports)) {
self::$transports = self::DEFAULT_TRANSPORTS;
}
// Find us a working transport.
foreach (self::$transports as $class) {
if (!class_exists($class)) {
continue;
}
$result = $class::test($capabilities);
if ($result === true) {
self::$transport[$cap_string] = $class;
break;
}
}
return self::$transport[$cap_string];
}
/**
* Get a working transport.
*
* @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
* @return \WpOrg\Requests\Transport
* @throws \WpOrg\Requests\Exception If no valid transport is found (`notransport`).
*/
protected static function get_transport(array $capabilities = []) {
$class = self::get_transport_class($capabilities);
if ($class === '') {
throw new Exception('No working transports found', 'notransport', self::$transports);
}
return new $class();
}
/**
* Checks to see if we have a transport for the capabilities requested.
*
* Supported capabilities can be found in the {@see \WpOrg\Requests\Capability}
* interface as constants.
*
* Example usage:
* `Requests::has_capabilities([Capability::SSL => true])`.
*
* @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
* @return bool Whether the transport has the requested capabilities.
*/
public static function has_capabilities(array $capabilities = []) {
return self::get_transport_class($capabilities) !== '';
}
/**#@+
* @see \WpOrg\Requests\Requests::request()
* @param string $url
* @param array $headers
* @param array $options
* @return \WpOrg\Requests\Response
*/
/**
* Send a GET request
*/
public static function get($url, $headers = [], $options = []) {
return self::request($url, $headers, null, self::GET, $options);
}
/**
* Send a HEAD request
*/
public static function head($url, $headers = [], $options = []) {
return self::request($url, $headers, null, self::HEAD, $options);
}
/**
* Send a DELETE request
*/
public static function delete($url, $headers = [], $options = []) {
return self::request($url, $headers, null, self::DELETE, $options);
}
/**
* Send a TRACE request
*/
public static function trace($url, $headers = [], $options = []) {
return self::request($url, $headers, null, self::TRACE, $options);
}
/**#@-*/
/**#@+
* @see \WpOrg\Requests\Requests::request()
* @param string $url
* @param array $headers
* @param array $data
* @param array $options
* @return \WpOrg\Requests\Response
*/
/**
* Send a POST request
*/
public static function post($url, $headers = [], $data = [], $options = []) {
return self::request($url, $headers, $data, self::POST, $options);
}
/**
* Send a PUT request
*/
public static function put($url, $headers = [], $data = [], $options = []) {
return self::request($url, $headers, $data, self::PUT, $options);
}
/**
* Send an OPTIONS request
*/
public static function options($url, $headers = [], $data = [], $options = []) {
return self::request($url, $headers, $data, self::OPTIONS, $options);
}
/**
* Send a PATCH request
*
* Note: Unlike {@see \WpOrg\Requests\Requests::post()} and {@see \WpOrg\Requests\Requests::put()},
* `$headers` is required, as the specification recommends that should send an ETag
*
* @link https://tools.ietf.org/html/rfc5789
*/
public static function patch($url, $headers, $data = [], $options = []) {
return self::request($url, $headers, $data, self::PATCH, $options);
}
/**#@-*/
/**
* Main interface for HTTP requests
*
* This method initiates a request and sends it via a transport before
* parsing.
*
* The `$options` parameter takes an associative array with the following
* options:
*
* - `timeout`: How long should we wait for a response?
* Note: for cURL, a minimum of 1 second applies, as DNS resolution
* operates at second-resolution only.
* (float, seconds with a millisecond precision, default: 10, example: 0.01)
* - `connect_timeout`: How long should we wait while trying to connect?
* (float, seconds with a millisecond precision, default: 10, example: 0.01)
* - `useragent`: Useragent to send to the server
* (string, default: php-requests/$version)
* - `follow_redirects`: Should we follow 3xx redirects?
* (boolean, default: true)
* - `redirects`: How many times should we redirect before erroring?
* (integer, default: 10)
* - `blocking`: Should we block processing on this request?
* (boolean, default: true)
* - `filename`: File to stream the body to instead.
* (string|boolean, default: false)
* - `auth`: Authentication handler or array of user/password details to use
* for Basic authentication
* (\WpOrg\Requests\Auth|array|boolean, default: false)
* - `proxy`: Proxy details to use for proxy by-passing and authentication
* (\WpOrg\Requests\Proxy|array|string|boolean, default: false)
* - `max_bytes`: Limit for the response body size.
* (integer|boolean, default: false)
* - `idn`: Enable IDN parsing
* (boolean, default: true)
* - `transport`: Custom transport. Either a class name, or a
* transport object. Defaults to the first working transport from
* {@see \WpOrg\Requests\Requests::getTransport()}
* (string|\WpOrg\Requests\Transport, default: {@see \WpOrg\Requests\Requests::getTransport()})
* - `hooks`: Hooks handler.
* (\WpOrg\Requests\HookManager, default: new WpOrg\Requests\Hooks())
* - `verify`: Should we verify SSL certificates? Allows passing in a custom
* certificate file as a string. (Using true uses the system-wide root
* certificate store instead, but this may have different behaviour
* across transports.)
* (string|boolean, default: certificates/cacert.pem)
* - `verifyname`: Should we verify the common name in the SSL certificate?
* (boolean, default: true)
* - `data_format`: How should we send the `$data` parameter?
* (string, one of 'query' or 'body', default: 'query' for
* HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH)
*
* @param string|Stringable $url URL to request
* @param array $headers Extra headers to send with the request
* @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
* @param string $type HTTP request type (use Requests constants)
* @param array $options Options for the request (see description for more information)
* @return \WpOrg\Requests\Response
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $type argument is not a string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
* @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`)
*/
public static function request($url, $headers = [], $data = [], $type = self::GET, $options = []) {
if (InputValidator::is_string_or_stringable($url) === false) {
throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
}
if (is_string($type) === false) {
throw InvalidArgument::create(4, '$type', 'string', gettype($type));
}
if (is_array($options) === false) {
throw InvalidArgument::create(5, '$options', 'array', gettype($options));
}
if (empty($options['type'])) {
$options['type'] = $type;
}
$options = array_merge(self::get_default_options(), $options);
self::set_defaults($url, $headers, $data, $type, $options);
$options['hooks']->dispatch('requests.before_request', [&$url, &$headers, &$data, &$type, &$options]);
if (!empty($options['transport'])) {
$transport = $options['transport'];
if (is_string($options['transport'])) {
$transport = new $transport();
}
} else {
$need_ssl = (stripos($url, 'https://') === 0);
$capabilities = [Capability::SSL => $need_ssl];
$transport = self::get_transport($capabilities);
}
$response = $transport->request($url, $headers, $data, $options);
$options['hooks']->dispatch('requests.before_parse', [&$response, $url, $headers, $data, $type, $options]);
return self::parse_response($response, $url, $headers, $data, $options);
}
/**
* Send multiple HTTP requests simultaneously
*
* The `$requests` parameter takes an associative or indexed array of
* request fields. The key of each request can be used to match up the
* request with the returned data, or with the request passed into your
* `multiple.request.complete` callback.
*
* The request fields value is an associative array with the following keys:
*
* - `url`: Request URL Same as the `$url` parameter to
* {@see \WpOrg\Requests\Requests::request()}
* (string, required)
* - `headers`: Associative array of header fields. Same as the `$headers`
* parameter to {@see \WpOrg\Requests\Requests::request()}
* (array, default: `array()`)
* - `data`: Associative array of data fields or a string. Same as the
* `$data` parameter to {@see \WpOrg\Requests\Requests::request()}
* (array|string, default: `array()`)
* - `type`: HTTP request type (use \WpOrg\Requests\Requests constants). Same as the `$type`
* parameter to {@see \WpOrg\Requests\Requests::request()}
* (string, default: `\WpOrg\Requests\Requests::GET`)
* - `cookies`: Associative array of cookie name to value, or cookie jar.
* (array|\WpOrg\Requests\Cookie\Jar)
*
* If the `$options` parameter is specified, individual requests will
* inherit options from it. This can be used to use a single hooking system,
* or set all the types to `\WpOrg\Requests\Requests::POST`, for example.
*
* In addition, the `$options` parameter takes the following global options:
*
* - `complete`: A callback for when a request is complete. Takes two
* parameters, a \WpOrg\Requests\Response/\WpOrg\Requests\Exception reference, and the
* ID from the request array (Note: this can also be overridden on a
* per-request basis, although that's a little silly)
* (callback)
*
* @param array $requests Requests data (see description for more information)
* @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()})
* @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object)
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
*/
public static function request_multiple($requests, $options = []) {
if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
}
if (is_array($options) === false) {
throw InvalidArgument::create(2, '$options', 'array', gettype($options));
}
$options = array_merge(self::get_default_options(true), $options);
if (!empty($options['hooks'])) {
$options['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']);
if (!empty($options['complete'])) {
$options['hooks']->register('multiple.request.complete', $options['complete']);
}
}
foreach ($requests as $id => &$request) {
if (!isset($request['headers'])) {
$request['headers'] = [];
}
if (!isset($request['data'])) {
$request['data'] = [];
}
if (!isset($request['type'])) {
$request['type'] = self::GET;
}
if (!isset($request['options'])) {
$request['options'] = $options;
$request['options']['type'] = $request['type'];
} else {
if (empty($request['options']['type'])) {
$request['options']['type'] = $request['type'];
}
$request['options'] = array_merge($options, $request['options']);
}
self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']);
// Ensure we only hook in once
if ($request['options']['hooks'] !== $options['hooks']) {
$request['options']['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']);
if (!empty($request['options']['complete'])) {
$request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
}
}
}
unset($request);
if (!empty($options['transport'])) {
$transport = $options['transport'];
if (is_string($options['transport'])) {
$transport = new $transport();
}
} else {
$transport = self::get_transport();
}
$responses = $transport->request_multiple($requests, $options);
foreach ($responses as $id => &$response) {
// If our hook got messed with somehow, ensure we end up with the
// correct response
if (is_string($response)) {
$request = $requests[$id];
self::parse_multiple($response, $request);
$request['options']['hooks']->dispatch('multiple.request.complete', [&$response, $id]);
}
}
return $responses;
}
/**
* Get the default options
*
* @see \WpOrg\Requests\Requests::request() for values returned by this method
* @param boolean $multirequest Is this a multirequest?
* @return array Default option values
*/
protected static function get_default_options($multirequest = false) {
$defaults = static::OPTION_DEFAULTS;
$defaults['verify'] = self::$certificate_path;
if ($multirequest !== false) {
$defaults['complete'] = null;
}
return $defaults;
}
/**
* Get default certificate path.
*
* @return string Default certificate path.
*/
public static function get_certificate_path() {
return self::$certificate_path;
}
/**
* Set default certificate path.
*
* @param string|Stringable|bool $path Certificate path, pointing to a PEM file.
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or boolean.
*/
public static function set_certificate_path($path) {
if (InputValidator::is_string_or_stringable($path) === false && is_bool($path) === false) {
throw InvalidArgument::create(1, '$path', 'string|Stringable|bool', gettype($path));
}
self::$certificate_path = $path;
}
/**
* Set the default values
*
* The $options parameter is updated with the results.
*
* @param string $url URL to request
* @param array $headers Extra headers to send with the request
* @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
* @param string $type HTTP request type
* @param array $options Options for the request
* @return void
*
* @throws \WpOrg\Requests\Exception When the $url is not an http(s) URL.
*/
protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) {
throw new Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
}
if (empty($options['hooks'])) {
$options['hooks'] = new Hooks();
}
if (is_array($options['auth'])) {
$options['auth'] = new Basic($options['auth']);
}
if ($options['auth'] !== false) {
$options['auth']->register($options['hooks']);
}
if (is_string($options['proxy']) || is_array($options['proxy'])) {
$options['proxy'] = new Http($options['proxy']);
}
if ($options['proxy'] !== false) {
$options['proxy']->register($options['hooks']);
}
if (is_array($options['cookies'])) {
$options['cookies'] = new Jar($options['cookies']);
} elseif (empty($options['cookies'])) {
$options['cookies'] = new Jar();
}
if ($options['cookies'] !== false) {
$options['cookies']->register($options['hooks']);
}
if ($options['idn'] !== false) {
$iri = new Iri($url);
$iri->host = IdnaEncoder::encode($iri->ihost);
$url = $iri->uri;
}
// Massage the type to ensure we support it.
$type = strtoupper($type);
if (!isset($options['data_format'])) {
if (in_array($type, [self::HEAD, self::GET, self::DELETE], true)) {
$options['data_format'] = 'query';
} else {
$options['data_format'] = 'body';
}
}
}
/**
* HTTP response parser
*
* @param string $headers Full response text including headers and body
* @param string $url Original request URL
* @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects
* @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
* @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
* @return \WpOrg\Requests\Response
*
* @throws \WpOrg\Requests\Exception On missing head/body separator (`requests.no_crlf_separator`)
* @throws \WpOrg\Requests\Exception On missing head/body separator (`noversion`)
* @throws \WpOrg\Requests\Exception On missing head/body separator (`toomanyredirects`)
*/
protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
$return = new Response();
if (!$options['blocking']) {
return $return;
}
$return->raw = $headers;
$return->url = (string) $url;
$return->body = '';
if (!$options['filename']) {
$pos = strpos($headers, "\r\n\r\n");
if ($pos === false) {
// Crap!
throw new Exception('Missing header/body separator', 'requests.no_crlf_separator');
}
$headers = substr($return->raw, 0, $pos);
// Headers will always be separated from the body by two new lines - `\n\r\n\r`.
$body = substr($return->raw, $pos + 4);
if (!empty($body)) {
$return->body = $body;
}
}
// Pretend CRLF = LF for compatibility (RFC 2616, section 19.3)
$headers = str_replace("\r\n", "\n", $headers);
// Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2)
$headers = preg_replace('/\n[ \t]/', ' ', $headers);
$headers = explode("\n", $headers);
preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches);
if (empty($matches)) {
throw new Exception('Response could not be parsed', 'noversion', $headers);
}
$return->protocol_version = (float) $matches[1];
$return->status_code = (int) $matches[2];
if ($return->status_code >= 200 && $return->status_code < 300) {
$return->success = true;
}
foreach ($headers as $header) {
list($key, $value) = explode(':', $header, 2);
$value = trim($value);
preg_replace('#(\s+)#i', ' ', $value);
$return->headers[$key] = $value;
}
if (isset($return->headers['transfer-encoding'])) {
$return->body = self::decode_chunked($return->body);
unset($return->headers['transfer-encoding']);
}
if (isset($return->headers['content-encoding'])) {
$return->body = self::decompress($return->body);
}
//fsockopen and cURL compatibility
if (isset($return->headers['connection'])) {
unset($return->headers['connection']);
}
$options['hooks']->dispatch('requests.before_redirect_check', [&$return, $req_headers, $req_data, $options]);
if ($return->is_redirect() && $options['follow_redirects'] === true) {
if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
if ($return->status_code === 303) {
$options['type'] = self::GET;
}
$options['redirected']++;
$location = $return->headers['location'];
if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) {
// relative redirect, for compatibility make it absolute
$location = Iri::absolutize($url, $location);
$location = $location->uri;
}
$hook_args = [
&$location,
&$req_headers,
&$req_data,
&$options,
$return,
];
$options['hooks']->dispatch('requests.before_redirect', $hook_args);
$redirected = self::request($location, $req_headers, $req_data, $options['type'], $options);
$redirected->history[] = $return;
return $redirected;
} elseif ($options['redirected'] >= $options['redirects']) {
throw new Exception('Too many redirects', 'toomanyredirects', $return);
}
}
$return->redirects = $options['redirected'];
$options['hooks']->dispatch('requests.after_request', [&$return, $req_headers, $req_data, $options]);
return $return;
}
/**
* Callback for `transport.internal.parse_response`
*
* Internal use only. Converts a raw HTTP response to a \WpOrg\Requests\Response
* while still executing a multiple request.
*
* `$response` is either set to a \WpOrg\Requests\Response instance, or a \WpOrg\Requests\Exception object
*
* @param string $response Full response text including headers and body (will be overwritten with Response instance)
* @param array $request Request data as passed into {@see \WpOrg\Requests\Requests::request_multiple()}
* @return void
*/
public static function parse_multiple(&$response, $request) {
try {
$url = $request['url'];
$headers = $request['headers'];
$data = $request['data'];
$options = $request['options'];
$response = self::parse_response($response, $url, $headers, $data, $options);
} catch (Exception $e) {
$response = $e;
}
}
/**
* Decoded a chunked body as per RFC 2616
*
* @link https://tools.ietf.org/html/rfc2616#section-3.6.1
* @param string $data Chunked body
* @return string Decoded body
*/
protected static function decode_chunked($data) {
if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
return $data;
}
$decoded = '';
$encoded = $data;
while (true) {
$is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
if (!$is_chunked) {
// Looks like it's not chunked after all
return $data;
}
$length = hexdec(trim($matches[1]));
if ($length === 0) {
// Ignore trailer headers
return $decoded;
}
$chunk_length = strlen($matches[0]);
$decoded .= substr($encoded, $chunk_length, $length);
$encoded = substr($encoded, $chunk_length + $length + 2);
if (trim($encoded) === '0' || empty($encoded)) {
return $decoded;
}
}
// We'll never actually get down here
// @codeCoverageIgnoreStart
}
// @codeCoverageIgnoreEnd
/**
* Convert a key => value array to a 'key: value' array for headers
*
* @param iterable $dictionary Dictionary of header values
* @return array List of headers
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not iterable.
*/
public static function flatten($dictionary) {
if (InputValidator::is_iterable($dictionary) === false) {
throw InvalidArgument::create(1, '$dictionary', 'iterable', gettype($dictionary));
}
$return = [];
foreach ($dictionary as $key => $value) {
$return[] = sprintf('%s: %s', $key, $value);
}
return $return;
}
/**
* Decompress an encoded body
*
* Implements gzip, compress and deflate. Guesses which it is by attempting
* to decode.
*
* @param string $data Compressed data in one of the above formats
* @return string Decompressed string
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string.
*/
public static function decompress($data) {
if (is_string($data) === false) {
throw InvalidArgument::create(1, '$data', 'string', gettype($data));
}
if (trim($data) === '') {
// Empty body does not need further processing.
return $data;
}
$marker = substr($data, 0, 2);
if (!isset(self::$magic_compression_headers[$marker])) {
// Not actually compressed. Probably cURL ruining this for us.
return $data;
}
if (function_exists('gzdecode')) {
$decoded = @gzdecode($data);
if ($decoded !== false) {
return $decoded;
}
}
if (function_exists('gzinflate')) {
$decoded = @gzinflate($data);
if ($decoded !== false) {
return $decoded;
}
}
$decoded = self::compatible_gzinflate($data);
if ($decoded !== false) {
return $decoded;
}
if (function_exists('gzuncompress')) {
$decoded = @gzuncompress($data);
if ($decoded !== false) {
return $decoded;
}
}
return $data;
}
/**
* Decompression of deflated string while staying compatible with the majority of servers.
*
* Certain Servers will return deflated data with headers which PHP's gzinflate()
* function cannot handle out of the box. The following function has been created from
* various snippets on the gzinflate() PHP documentation.
*
* Warning: Magic numbers within. Due to the potential different formats that the compressed
* data may be returned in, some "magic offsets" are needed to ensure proper decompression
* takes place. For a simple progmatic way to determine the magic offset in use, see:
* https://core.trac.wordpress.org/ticket/18273
*
* @since 1.6.0
* @link https://core.trac.wordpress.org/ticket/18273
* @link https://www.php.net/gzinflate#70875
* @link https://www.php.net/gzinflate#77336
*
* @param string $gz_data String to decompress.
* @return string|bool False on failure.
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string.
*/
public static function compatible_gzinflate($gz_data) {
if (is_string($gz_data) === false) {
throw InvalidArgument::create(1, '$gz_data', 'string', gettype($gz_data));
}
if (trim($gz_data) === '') {
return false;
}
// Compressed data might contain a full zlib header, if so strip it for
// gzinflate()
if (substr($gz_data, 0, 3) === "\x1f\x8b\x08") {
$i = 10;
$flg = ord(substr($gz_data, 3, 1));
if ($flg > 0) {
if ($flg & 4) {
list($xlen) = unpack('v', substr($gz_data, $i, 2));
$i += 2 + $xlen;
}
if ($flg & 8) {
$i = strpos($gz_data, "\0", $i) + 1;
}
if ($flg & 16) {
$i = strpos($gz_data, "\0", $i) + 1;
}
if ($flg & 2) {
$i += 2;
}
}
$decompressed = self::compatible_gzinflate(substr($gz_data, $i));
if ($decompressed !== false) {
return $decompressed;
}
}
// If the data is Huffman Encoded, we must first strip the leading 2
// byte Huffman marker for gzinflate()
// The response is Huffman coded by many compressors such as
// java.util.zip.Deflater, Ruby's Zlib::Deflate, and .NET's
// System.IO.Compression.DeflateStream.
//
// See https://decompres.blogspot.com/ for a quick explanation of this
// data type
$huffman_encoded = false;
// low nibble of first byte should be 0x08
list(, $first_nibble) = unpack('h', $gz_data);
// First 2 bytes should be divisible by 0x1F
list(, $first_two_bytes) = unpack('n', $gz_data);
if ($first_nibble === 0x08 && ($first_two_bytes % 0x1F) === 0) {
$huffman_encoded = true;
}
if ($huffman_encoded) {
$decompressed = @gzinflate(substr($gz_data, 2));
if ($decompressed !== false) {
return $decompressed;
}
}
if (substr($gz_data, 0, 4) === "\x50\x4b\x03\x04") {
// ZIP file format header
// Offset 6: 2 bytes, General-purpose field
// Offset 26: 2 bytes, filename length
// Offset 28: 2 bytes, optional field length
// Offset 30: Filename field, followed by optional field, followed
// immediately by data
list(, $general_purpose_flag) = unpack('v', substr($gz_data, 6, 2));
// If the file has been compressed on the fly, 0x08 bit is set of
// the general purpose field. We can use this to differentiate
// between a compressed document, and a ZIP file
$zip_compressed_on_the_fly = ((0x08 & $general_purpose_flag) === 0x08);
if (!$zip_compressed_on_the_fly) {
// Don't attempt to decode a compressed zip file
return $gz_data;
}
// Determine the first byte of data, based on the above ZIP header
// offsets:
$first_file_start = array_sum(unpack('v2', substr($gz_data, 26, 4)));
$decompressed = @gzinflate(substr($gz_data, 30 + $first_file_start));
if ($decompressed !== false) {
return $decompressed;
}
return false;
}
// Finally fall back to straight gzinflate
$decompressed = @gzinflate($gz_data);
if ($decompressed !== false) {
return $decompressed;
}
// Fallback for all above failing, not expected, but included for
// debugging and preventing regressions and to track stats
$decompressed = @gzinflate(substr($gz_data, 2));
if ($decompressed !== false) {
return $decompressed;
}
return false;
}
}
<?php
/**
* HTTP Proxy connection interface
*
* @package Requests\Proxy
* @since 1.6
*/
namespace WpOrg\Requests\Proxy;
use WpOrg\Requests\Exception\ArgumentCount;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Hooks;
use WpOrg\Requests\Proxy;
/**
* HTTP Proxy connection interface
*
* Provides a handler for connection via an HTTP proxy
*
* @package Requests\Proxy
* @since 1.6
*/
final class Http implements Proxy {
/**
* Proxy host and port
*
* Notation: "host:port" (eg 127.0.0.1:8080 or someproxy.com:3128)
*
* @var string
*/
public $proxy;
/**
* Username
*
* @var string
*/
public $user;
/**
* Password
*
* @var string
*/
public $pass;
/**
* Do we need to authenticate? (ie username & password have been provided)
*
* @var boolean
*/
public $use_authentication;
/**
* Constructor
*
* @since 1.6
*
* @param array|string|null $args Proxy as a string or an array of proxy, user and password.
* When passed as an array, must have exactly one (proxy)
* or three elements (proxy, user, password).
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array, a string or null.
* @throws \WpOrg\Requests\Exception\ArgumentCount On incorrect number of arguments (`proxyhttpbadargs`)
*/
public function __construct($args = null) {
if (is_string($args)) {
$this->proxy = $args;
} elseif (is_array($args)) {
if (count($args) === 1) {
list($this->proxy) = $args;
} elseif (count($args) === 3) {
list($this->proxy, $this->user, $this->pass) = $args;
$this->use_authentication = true;
} else {
throw ArgumentCount::create(
'an array with exactly one element or exactly three elements',
count($args),
'proxyhttpbadargs'
);
}
} elseif ($args !== null) {
throw InvalidArgument::create(1, '$args', 'array|string|null', gettype($args));
}
}
/**
* Register the necessary callbacks
*
* @since 1.6
* @see \WpOrg\Requests\Proxy\Http::curl_before_send()
* @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_socket()
* @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_host_path()
* @see \WpOrg\Requests\Proxy\Http::fsockopen_header()
* @param \WpOrg\Requests\Hooks $hooks Hook system
*/
public function register(Hooks $hooks) {
$hooks->register('curl.before_send', [$this, 'curl_before_send']);
$hooks->register('fsockopen.remote_socket', [$this, 'fsockopen_remote_socket']);
$hooks->register('fsockopen.remote_host_path', [$this, 'fsockopen_remote_host_path']);
if ($this->use_authentication) {
$hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']);
}
}
/**
* Set cURL parameters before the data is sent
*
* @since 1.6
* @param resource|\CurlHandle $handle cURL handle
*/
public function curl_before_send(&$handle) {
curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_setopt($handle, CURLOPT_PROXY, $this->proxy);
if ($this->use_authentication) {
curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string());
}
}
/**
* Alter remote socket information before opening socket connection
*
* @since 1.6
* @param string $remote_socket Socket connection string
*/
public function fsockopen_remote_socket(&$remote_socket) {
$remote_socket = $this->proxy;
}
/**
* Alter remote path before getting stream data
*
* @since 1.6
* @param string $path Path to send in HTTP request string ("GET ...")
* @param string $url Full URL we're requesting
*/
public function fsockopen_remote_host_path(&$path, $url) {
$path = $url;
}
/**
* Add extra headers to the request before sending
*
* @since 1.6
* @param string $out HTTP header string
*/
public function fsockopen_header(&$out) {
$out .= sprintf("Proxy-Authorization: Basic %s\r\n", base64_encode($this->get_auth_string()));
}
/**
* Get the authentication string (user:pass)
*
* @since 1.6
* @return string
*/
public function get_auth_string() {
return $this->user . ':' . $this->pass;
}
}
[02-Dec-2025 10:42:20 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\Proxy" not found in /home/coopserp/public_html/wp-includes/Requests/src/Proxy/Http.php:24
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Proxy/Http.php on line 24
[02-Dec-2025 10:42:22 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\Transport" not found in /home/coopserp/public_html/wp-includes/Requests/src/Transport/Curl.php:25
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Transport/Curl.php on line 25
[02-Dec-2025 10:42:22 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\Transport" not found in /home/coopserp/public_html/wp-includes/Requests/src/Transport/Fsockopen.php:25
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Transport/Fsockopen.php on line 25
[06-Mar-2026 12:45:01 America/Bogota] PHP Fatal error: Uncaught Error: Interface "WpOrg\Requests\Transport" not found in /home/coopserp/public_html/wp-includes/Requests/src/Transport/Curl.php:25
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Transport/Curl.php on line 25
<?php
/**
* cURL HTTP transport
*
* @package Requests\Transport
*/
namespace WpOrg\Requests\Transport;
use RecursiveArrayIterator;
use RecursiveIteratorIterator;
use WpOrg\Requests\Capability;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Exception\Transport\Curl as CurlException;
use WpOrg\Requests\Requests;
use WpOrg\Requests\Transport;
use WpOrg\Requests\Utility\InputValidator;
/**
* cURL HTTP transport
*
* @package Requests\Transport
*/
final class Curl implements Transport {
const CURL_7_10_5 = 0x070A05;
const CURL_7_16_2 = 0x071002;
/**
* Raw HTTP data
*
* @var string
*/
public $headers = '';
/**
* Raw body data
*
* @var string
*/
public $response_data = '';
/**
* Information on the current request
*
* @var array cURL information array, see {@link https://www.php.net/curl_getinfo}
*/
public $info;
/**
* cURL version number
*
* @var int
*/
public $version;
/**
* cURL handle
*
* @var resource|\CurlHandle Resource in PHP < 8.0, Instance of CurlHandle in PHP >= 8.0.
*/
private $handle;
/**
* Hook dispatcher instance
*
* @var \WpOrg\Requests\Hooks
*/
private $hooks;
/**
* Have we finished the headers yet?
*
* @var boolean
*/
private $done_headers = false;
/**
* If streaming to a file, keep the file pointer
*
* @var resource
*/
private $stream_handle;
/**
* How many bytes are in the response body?
*
* @var int
*/
private $response_bytes;
/**
* What's the maximum number of bytes we should keep?
*
* @var int|bool Byte count, or false if no limit.
*/
private $response_byte_limit;
/**
* Constructor
*/
public function __construct() {
$curl = curl_version();
$this->version = $curl['version_number'];
$this->handle = curl_init();
curl_setopt($this->handle, CURLOPT_HEADER, false);
curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
if ($this->version >= self::CURL_7_10_5) {
curl_setopt($this->handle, CURLOPT_ENCODING, '');
}
if (defined('CURLOPT_PROTOCOLS')) {
// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_protocolsFound
curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
}
if (defined('CURLOPT_REDIR_PROTOCOLS')) {
// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_redir_protocolsFound
curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
}
}
/**
* Destructor
*/
public function __destruct() {
if (is_resource($this->handle)) {
curl_close($this->handle);
}
}
/**
* Perform a request
*
* @param string|Stringable $url URL to request
* @param array $headers Associative array of request headers
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
* @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
* @return string Raw HTTP result
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
* @throws \WpOrg\Requests\Exception On a cURL error (`curlerror`)
*/
public function request($url, $headers = [], $data = [], $options = []) {
if (InputValidator::is_string_or_stringable($url) === false) {
throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
}
if (is_array($headers) === false) {
throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
}
if (!is_array($data) && !is_string($data)) {
if ($data === null) {
$data = '';
} else {
throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
}
}
if (is_array($options) === false) {
throw InvalidArgument::create(4, '$options', 'array', gettype($options));
}
$this->hooks = $options['hooks'];
$this->setup_handle($url, $headers, $data, $options);
$options['hooks']->dispatch('curl.before_send', [&$this->handle]);
if ($options['filename'] !== false) {
// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception.
$this->stream_handle = @fopen($options['filename'], 'wb');
if ($this->stream_handle === false) {
$error = error_get_last();
throw new Exception($error['message'], 'fopen');
}
}
$this->response_data = '';
$this->response_bytes = 0;
$this->response_byte_limit = false;
if ($options['max_bytes'] !== false) {
$this->response_byte_limit = $options['max_bytes'];
}
if (isset($options['verify'])) {
if ($options['verify'] === false) {
curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0);
} elseif (is_string($options['verify'])) {
curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']);
}
}
if (isset($options['verifyname']) && $options['verifyname'] === false) {
curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
}
curl_exec($this->handle);
$response = $this->response_data;
$options['hooks']->dispatch('curl.after_send', []);
if (curl_errno($this->handle) === CURLE_WRITE_ERROR || curl_errno($this->handle) === CURLE_BAD_CONTENT_ENCODING) {
// Reset encoding and try again
curl_setopt($this->handle, CURLOPT_ENCODING, 'none');
$this->response_data = '';
$this->response_bytes = 0;
curl_exec($this->handle);
$response = $this->response_data;
}
$this->process_response($response, $options);
// Need to remove the $this reference from the curl handle.
// Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called.
curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
return $this->headers;
}
/**
* Send multiple requests simultaneously
*
* @param array $requests Request data
* @param array $options Global options
* @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
*/
public function request_multiple($requests, $options) {
// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
if (empty($requests)) {
return [];
}
if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
}
if (is_array($options) === false) {
throw InvalidArgument::create(2, '$options', 'array', gettype($options));
}
$multihandle = curl_multi_init();
$subrequests = [];
$subhandles = [];
$class = get_class($this);
foreach ($requests as $id => $request) {
$subrequests[$id] = new $class();
$subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
$request['options']['hooks']->dispatch('curl.before_multi_add', [&$subhandles[$id]]);
curl_multi_add_handle($multihandle, $subhandles[$id]);
}
$completed = 0;
$responses = [];
$subrequestcount = count($subrequests);
$request['options']['hooks']->dispatch('curl.before_multi_exec', [&$multihandle]);
do {
$active = 0;
do {
$status = curl_multi_exec($multihandle, $active);
} while ($status === CURLM_CALL_MULTI_PERFORM);
$to_process = [];
// Read the information as needed
while ($done = curl_multi_info_read($multihandle)) {
$key = array_search($done['handle'], $subhandles, true);
if (!isset($to_process[$key])) {
$to_process[$key] = $done;
}
}
// Parse the finished requests before we start getting the new ones
foreach ($to_process as $key => $done) {
$options = $requests[$key]['options'];
if ($done['result'] !== CURLE_OK) {
//get error string for handle.
$reason = curl_error($done['handle']);
$exception = new CurlException(
$reason,
CurlException::EASY,
$done['handle'],
$done['result']
);
$responses[$key] = $exception;
$options['hooks']->dispatch('transport.internal.parse_error', [&$responses[$key], $requests[$key]]);
} else {
$responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);
$options['hooks']->dispatch('transport.internal.parse_response', [&$responses[$key], $requests[$key]]);
}
curl_multi_remove_handle($multihandle, $done['handle']);
curl_close($done['handle']);
if (!is_string($responses[$key])) {
$options['hooks']->dispatch('multiple.request.complete', [&$responses[$key], $key]);
}
$completed++;
}
} while ($active || $completed < $subrequestcount);
$request['options']['hooks']->dispatch('curl.after_multi_exec', [&$multihandle]);
curl_multi_close($multihandle);
return $responses;
}
/**
* Get the cURL handle for use in a multi-request
*
* @param string $url URL to request
* @param array $headers Associative array of request headers
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
* @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
* @return resource|\CurlHandle Subrequest's cURL handle
*/
public function &get_subrequest_handle($url, $headers, $data, $options) {
$this->setup_handle($url, $headers, $data, $options);
if ($options['filename'] !== false) {
$this->stream_handle = fopen($options['filename'], 'wb');
}
$this->response_data = '';
$this->response_bytes = 0;
$this->response_byte_limit = false;
if ($options['max_bytes'] !== false) {
$this->response_byte_limit = $options['max_bytes'];
}
$this->hooks = $options['hooks'];
return $this->handle;
}
/**
* Setup the cURL handle for the given data
*
* @param string $url URL to request
* @param array $headers Associative array of request headers
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
* @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
*/
private function setup_handle($url, $headers, $data, $options) {
$options['hooks']->dispatch('curl.before_request', [&$this->handle]);
// Force closing the connection for old versions of cURL (<7.22).
if (!isset($headers['Connection'])) {
$headers['Connection'] = 'close';
}
/**
* Add "Expect" header.
*
* By default, cURL adds a "Expect: 100-Continue" to most requests. This header can
* add as much as a second to the time it takes for cURL to perform a request. To
* prevent this, we need to set an empty "Expect" header. To match the behaviour of
* Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use
* HTTP/1.1.
*
* https://curl.se/mail/lib-2017-07/0013.html
*/
if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) {
$headers['Expect'] = $this->get_expect_header($data);
}
$headers = Requests::flatten($headers);
if (!empty($data)) {
$data_format = $options['data_format'];
if ($data_format === 'query') {
$url = self::format_get($url, $data);
$data = '';
} elseif (!is_string($data)) {
$data = http_build_query($data, '', '&');
}
}
switch ($options['type']) {
case Requests::POST:
curl_setopt($this->handle, CURLOPT_POST, true);
curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
break;
case Requests::HEAD:
curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
curl_setopt($this->handle, CURLOPT_NOBODY, true);
break;
case Requests::TRACE:
curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
break;
case Requests::PATCH:
case Requests::PUT:
case Requests::DELETE:
case Requests::OPTIONS:
default:
curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
if (!empty($data)) {
curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
}
}
// cURL requires a minimum timeout of 1 second when using the system
// DNS resolver, as it uses `alarm()`, which is second resolution only.
// There's no way to detect which DNS resolver is being used from our
// end, so we need to round up regardless of the supplied timeout.
//
// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609
$timeout = max($options['timeout'], 1);
if (is_int($timeout) || $this->version < self::CURL_7_16_2) {
curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout));
} else {
// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_timeout_msFound
curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000));
}
if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
} else {
// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_connecttimeout_msFound
curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
}
curl_setopt($this->handle, CURLOPT_URL, $url);
curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
if (!empty($headers)) {
curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
}
if ($options['protocol_version'] === 1.1) {
curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
} else {
curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
}
if ($options['blocking'] === true) {
curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, [$this, 'stream_headers']);
curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, [$this, 'stream_body']);
curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
}
}
/**
* Process a response
*
* @param string $response Response data from the body
* @param array $options Request options
* @return string|false HTTP response data including headers. False if non-blocking.
* @throws \WpOrg\Requests\Exception If the request resulted in a cURL error.
*/
public function process_response($response, $options) {
if ($options['blocking'] === false) {
$fake_headers = '';
$options['hooks']->dispatch('curl.after_request', [&$fake_headers]);
return false;
}
if ($options['filename'] !== false && $this->stream_handle) {
fclose($this->stream_handle);
$this->headers = trim($this->headers);
} else {
$this->headers .= $response;
}
if (curl_errno($this->handle)) {
$error = sprintf(
'cURL error %s: %s',
curl_errno($this->handle),
curl_error($this->handle)
);
throw new Exception($error, 'curlerror', $this->handle);
}
$this->info = curl_getinfo($this->handle);
$options['hooks']->dispatch('curl.after_request', [&$this->headers, &$this->info]);
return $this->headers;
}
/**
* Collect the headers as they are received
*
* @param resource|\CurlHandle $handle cURL handle
* @param string $headers Header string
* @return integer Length of provided header
*/
public function stream_headers($handle, $headers) {
// Why do we do this? cURL will send both the final response and any
// interim responses, such as a 100 Continue. We don't need that.
// (We may want to keep this somewhere just in case)
if ($this->done_headers) {
$this->headers = '';
$this->done_headers = false;
}
$this->headers .= $headers;
if ($headers === "\r\n") {
$this->done_headers = true;
}
return strlen($headers);
}
/**
* Collect data as it's received
*
* @since 1.6.1
*
* @param resource|\CurlHandle $handle cURL handle
* @param string $data Body data
* @return integer Length of provided data
*/
public function stream_body($handle, $data) {
$this->hooks->dispatch('request.progress', [$data, $this->response_bytes, $this->response_byte_limit]);
$data_length = strlen($data);
// Are we limiting the response size?
if ($this->response_byte_limit) {
if ($this->response_bytes === $this->response_byte_limit) {
// Already at maximum, move on
return $data_length;
}
if (($this->response_bytes + $data_length) > $this->response_byte_limit) {
// Limit the length
$limited_length = ($this->response_byte_limit - $this->response_bytes);
$data = substr($data, 0, $limited_length);
}
}
if ($this->stream_handle) {
fwrite($this->stream_handle, $data);
} else {
$this->response_data .= $data;
}
$this->response_bytes += strlen($data);
return $data_length;
}
/**
* Format a URL given GET data
*
* @param string $url Original URL.
* @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query}
* @return string URL with data
*/
private static function format_get($url, $data) {
if (!empty($data)) {
$query = '';
$url_parts = parse_url($url);
if (empty($url_parts['query'])) {
$url_parts['query'] = '';
} else {
$query = $url_parts['query'];
}
$query .= '&' . http_build_query($data, '', '&');
$query = trim($query, '&');
if (empty($url_parts['query'])) {
$url .= '?' . $query;
} else {
$url = str_replace($url_parts['query'], $query, $url);
}
}
return $url;
}
/**
* Self-test whether the transport can be used.
*
* The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
*
* @codeCoverageIgnore
* @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
* @return bool Whether the transport can be used.
*/
public static function test($capabilities = []) {
if (!function_exists('curl_init') || !function_exists('curl_exec')) {
return false;
}
// If needed, check that our installed curl version supports SSL
if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) {
$curl_version = curl_version();
if (!(CURL_VERSION_SSL & $curl_version['features'])) {
return false;
}
}
return true;
}
/**
* Get the correct "Expect" header for the given request data.
*
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
* @return string The "Expect" header.
*/
private function get_expect_header($data) {
if (!is_array($data)) {
return strlen((string) $data) >= 1048576 ? '100-Continue' : '';
}
$bytesize = 0;
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data));
foreach ($iterator as $datum) {
$bytesize += strlen((string) $datum);
if ($bytesize >= 1048576) {
return '100-Continue';
}
}
return '';
}
}
<?php
/**
* fsockopen HTTP transport
*
* @package Requests\Transport
*/
namespace WpOrg\Requests\Transport;
use WpOrg\Requests\Capability;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Port;
use WpOrg\Requests\Requests;
use WpOrg\Requests\Ssl;
use WpOrg\Requests\Transport;
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
use WpOrg\Requests\Utility\InputValidator;
/**
* fsockopen HTTP transport
*
* @package Requests\Transport
*/
final class Fsockopen implements Transport {
/**
* Second to microsecond conversion
*
* @var integer
*/
const SECOND_IN_MICROSECONDS = 1000000;
/**
* Raw HTTP data
*
* @var string
*/
public $headers = '';
/**
* Stream metadata
*
* @var array Associative array of properties, see {@link https://www.php.net/stream_get_meta_data}
*/
public $info;
/**
* What's the maximum number of bytes we should keep?
*
* @var int|bool Byte count, or false if no limit.
*/
private $max_bytes = false;
/**
* Cache for received connection errors.
*
* @var string
*/
private $connect_error = '';
/**
* Perform a request
*
* @param string|Stringable $url URL to request
* @param array $headers Associative array of request headers
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
* @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
* @return string Raw HTTP result
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
* @throws \WpOrg\Requests\Exception On failure to connect to socket (`fsockopenerror`)
* @throws \WpOrg\Requests\Exception On socket timeout (`timeout`)
*/
public function request($url, $headers = [], $data = [], $options = []) {
if (InputValidator::is_string_or_stringable($url) === false) {
throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
}
if (is_array($headers) === false) {
throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
}
if (!is_array($data) && !is_string($data)) {
if ($data === null) {
$data = '';
} else {
throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
}
}
if (is_array($options) === false) {
throw InvalidArgument::create(4, '$options', 'array', gettype($options));
}
$options['hooks']->dispatch('fsockopen.before_request');
$url_parts = parse_url($url);
if (empty($url_parts)) {
throw new Exception('Invalid URL.', 'invalidurl', $url);
}
$host = $url_parts['host'];
$context = stream_context_create();
$verifyname = false;
$case_insensitive_headers = new CaseInsensitiveDictionary($headers);
// HTTPS support
if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
$remote_socket = 'ssl://' . $host;
if (!isset($url_parts['port'])) {
$url_parts['port'] = Port::HTTPS;
}
$context_options = [
'verify_peer' => true,
'capture_peer_cert' => true,
];
$verifyname = true;
// SNI, if enabled (OpenSSL >=0.9.8j)
// phpcs:ignore PHPCompatibility.Constants.NewConstants.openssl_tlsext_server_nameFound
if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
$context_options['SNI_enabled'] = true;
if (isset($options['verifyname']) && $options['verifyname'] === false) {
$context_options['SNI_enabled'] = false;
}
}
if (isset($options['verify'])) {
if ($options['verify'] === false) {
$context_options['verify_peer'] = false;
$context_options['verify_peer_name'] = false;
$verifyname = false;
} elseif (is_string($options['verify'])) {
$context_options['cafile'] = $options['verify'];
}
}
if (isset($options['verifyname']) && $options['verifyname'] === false) {
$context_options['verify_peer_name'] = false;
$verifyname = false;
}
// Handle the PHP 8.4 deprecation (PHP 9.0 removal) of the function signature we use for stream_context_set_option().
// Ref: https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures#stream_context_set_option
if (function_exists('stream_context_set_options')) {
// PHP 8.3+.
stream_context_set_options($context, ['ssl' => $context_options]);
} else {
// PHP < 8.3.
stream_context_set_option($context, ['ssl' => $context_options]);
}
} else {
$remote_socket = 'tcp://' . $host;
}
$this->max_bytes = $options['max_bytes'];
if (!isset($url_parts['port'])) {
$url_parts['port'] = Port::HTTP;
}
$remote_socket .= ':' . $url_parts['port'];
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
set_error_handler([$this, 'connect_error_handler'], E_WARNING | E_NOTICE);
$options['hooks']->dispatch('fsockopen.remote_socket', [&$remote_socket]);
$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);
restore_error_handler();
if ($verifyname && !$this->verify_certificate_from_context($host, $context)) {
throw new Exception('SSL certificate did not match the requested domain name', 'ssl.no_match');
}
if (!$socket) {
if ($errno === 0) {
// Connection issue
throw new Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
}
throw new Exception($errstr, 'fsockopenerror', null, $errno);
}
$data_format = $options['data_format'];
if ($data_format === 'query') {
$path = self::format_get($url_parts, $data);
$data = '';
} else {
$path = self::format_get($url_parts, []);
}
$options['hooks']->dispatch('fsockopen.remote_host_path', [&$path, $url]);
$request_body = '';
$out = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']);
if ($options['type'] !== Requests::TRACE) {
if (is_array($data)) {
$request_body = http_build_query($data, '', '&');
} else {
$request_body = $data;
}
// Always include Content-length on POST requests to prevent
// 411 errors from some servers when the body is empty.
if (!empty($data) || $options['type'] === Requests::POST) {
if (!isset($case_insensitive_headers['Content-Length'])) {
$headers['Content-Length'] = strlen($request_body);
}
if (!isset($case_insensitive_headers['Content-Type'])) {
$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
}
}
}
if (!isset($case_insensitive_headers['Host'])) {
$out .= sprintf('Host: %s', $url_parts['host']);
$scheme_lower = strtolower($url_parts['scheme']);
if (($scheme_lower === 'http' && $url_parts['port'] !== Port::HTTP) || ($scheme_lower === 'https' && $url_parts['port'] !== Port::HTTPS)) {
$out .= ':' . $url_parts['port'];
}
$out .= "\r\n";
}
if (!isset($case_insensitive_headers['User-Agent'])) {
$out .= sprintf("User-Agent: %s\r\n", $options['useragent']);
}
$accept_encoding = $this->accept_encoding();
if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) {
$out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding);
}
$headers = Requests::flatten($headers);
if (!empty($headers)) {
$out .= implode("\r\n", $headers) . "\r\n";
}
$options['hooks']->dispatch('fsockopen.after_headers', [&$out]);
if (substr($out, -2) !== "\r\n") {
$out .= "\r\n";
}
if (!isset($case_insensitive_headers['Connection'])) {
$out .= "Connection: Close\r\n";
}
$out .= "\r\n" . $request_body;
$options['hooks']->dispatch('fsockopen.before_send', [&$out]);
fwrite($socket, $out);
$options['hooks']->dispatch('fsockopen.after_send', [$out]);
if (!$options['blocking']) {
fclose($socket);
$fake_headers = '';
$options['hooks']->dispatch('fsockopen.after_request', [&$fake_headers]);
return '';
}
$timeout_sec = (int) floor($options['timeout']);
if ($timeout_sec === $options['timeout']) {
$timeout_msec = 0;
} else {
$timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS;
}
stream_set_timeout($socket, $timeout_sec, $timeout_msec);
$response = '';
$body = '';
$headers = '';
$this->info = stream_get_meta_data($socket);
$size = 0;
$doingbody = false;
$download = false;
if ($options['filename']) {
// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception.
$download = @fopen($options['filename'], 'wb');
if ($download === false) {
$error = error_get_last();
throw new Exception($error['message'], 'fopen');
}
}
while (!feof($socket)) {
$this->info = stream_get_meta_data($socket);
if ($this->info['timed_out']) {
throw new Exception('fsocket timed out', 'timeout');
}
$block = fread($socket, Requests::BUFFER_SIZE);
if (!$doingbody) {
$response .= $block;
if (strpos($response, "\r\n\r\n")) {
list($headers, $block) = explode("\r\n\r\n", $response, 2);
$doingbody = true;
}
}
// Are we in body mode now?
if ($doingbody) {
$options['hooks']->dispatch('request.progress', [$block, $size, $this->max_bytes]);
$data_length = strlen($block);
if ($this->max_bytes) {
// Have we already hit a limit?
if ($size === $this->max_bytes) {
continue;
}
if (($size + $data_length) > $this->max_bytes) {
// Limit the length
$limited_length = ($this->max_bytes - $size);
$block = substr($block, 0, $limited_length);
}
}
$size += strlen($block);
if ($download) {
fwrite($download, $block);
} else {
$body .= $block;
}
}
}
$this->headers = $headers;
if ($download) {
fclose($download);
} else {
$this->headers .= "\r\n\r\n" . $body;
}
fclose($socket);
$options['hooks']->dispatch('fsockopen.after_request', [&$this->headers, &$this->info]);
return $this->headers;
}
/**
* Send multiple requests simultaneously
*
* @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see \WpOrg\Requests\Transport::request()}
* @param array $options Global options, see {@see \WpOrg\Requests\Requests::response()} for documentation
* @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
*/
public function request_multiple($requests, $options) {
// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
if (empty($requests)) {
return [];
}
if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
}
if (is_array($options) === false) {
throw InvalidArgument::create(2, '$options', 'array', gettype($options));
}
$responses = [];
$class = get_class($this);
foreach ($requests as $id => $request) {
try {
$handler = new $class();
$responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);
$request['options']['hooks']->dispatch('transport.internal.parse_response', [&$responses[$id], $request]);
} catch (Exception $e) {
$responses[$id] = $e;
}
if (!is_string($responses[$id])) {
$request['options']['hooks']->dispatch('multiple.request.complete', [&$responses[$id], $id]);
}
}
return $responses;
}
/**
* Retrieve the encodings we can accept
*
* @return string Accept-Encoding header value
*/
private static function accept_encoding() {
$type = [];
if (function_exists('gzinflate')) {
$type[] = 'deflate;q=1.0';
}
if (function_exists('gzuncompress')) {
$type[] = 'compress;q=0.5';
}
$type[] = 'gzip;q=0.5';
return implode(', ', $type);
}
/**
* Format a URL given GET data
*
* @param array $url_parts Array of URL parts as received from {@link https://www.php.net/parse_url}
* @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query}
* @return string URL with data
*/
private static function format_get($url_parts, $data) {
if (!empty($data)) {
if (empty($url_parts['query'])) {
$url_parts['query'] = '';
}
$url_parts['query'] .= '&' . http_build_query($data, '', '&');
$url_parts['query'] = trim($url_parts['query'], '&');
}
if (isset($url_parts['path'])) {
if (isset($url_parts['query'])) {
$get = $url_parts['path'] . '?' . $url_parts['query'];
} else {
$get = $url_parts['path'];
}
} else {
$get = '/';
}
return $get;
}
/**
* Error handler for stream_socket_client()
*
* @param int $errno Error number (e.g. E_WARNING)
* @param string $errstr Error message
*/
public function connect_error_handler($errno, $errstr) {
// Double-check we can handle it
if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
// Return false to indicate the default error handler should engage
return false;
}
$this->connect_error .= $errstr . "\n";
return true;
}
/**
* Verify the certificate against common name and subject alternative names
*
* Unfortunately, PHP doesn't check the certificate against the alternative
* names, leading things like 'https://www.github.com/' to be invalid.
* Instead
*
* @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
*
* @param string $host Host name to verify against
* @param resource $context Stream context
* @return bool
*
* @throws \WpOrg\Requests\Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`)
* @throws \WpOrg\Requests\Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
*/
public function verify_certificate_from_context($host, $context) {
$meta = stream_context_get_options($context);
// If we don't have SSL options, then we couldn't make the connection at
// all
if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) {
throw new Exception(rtrim($this->connect_error), 'ssl.connect_error');
}
$cert = openssl_x509_parse($meta['ssl']['peer_certificate']);
return Ssl::verify_certificate($host, $cert);
}
/**
* Self-test whether the transport can be used.
*
* The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
*
* @codeCoverageIgnore
* @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
* @return bool Whether the transport can be used.
*/
public static function test($capabilities = []) {
if (!function_exists('fsockopen')) {
return false;
}
// If needed, check that streams support SSL
if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) {
if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) {
return false;
}
}
return true;
}
}
<?php
/**
* SSL utilities for Requests
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;
/**
* SSL utilities for Requests
*
* Collection of utilities for working with and verifying SSL certificates.
*
* @package Requests\Utilities
*/
final class Ssl {
/**
* Verify the certificate against common name and subject alternative names
*
* Unfortunately, PHP doesn't check the certificate against the alternative
* names, leading things like 'https://www.github.com/' to be invalid.
*
* @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
*
* @param string|Stringable $host Host name to verify against
* @param array $cert Certificate data from openssl_x509_parse()
* @return bool
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $host argument is not a string or a stringable object.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cert argument is not an array or array accessible.
*/
public static function verify_certificate($host, $cert) {
if (InputValidator::is_string_or_stringable($host) === false) {
throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host));
}
if (InputValidator::has_array_access($cert) === false) {
throw InvalidArgument::create(2, '$cert', 'array|ArrayAccess', gettype($cert));
}
$has_dns_alt = false;
// Check the subjectAltName
if (!empty($cert['extensions']['subjectAltName'])) {
$altnames = explode(',', $cert['extensions']['subjectAltName']);
foreach ($altnames as $altname) {
$altname = trim($altname);
if (strpos($altname, 'DNS:') !== 0) {
continue;
}
$has_dns_alt = true;
// Strip the 'DNS:' prefix and trim whitespace
$altname = trim(substr($altname, 4));
// Check for a match
if (self::match_domain($host, $altname) === true) {
return true;
}
}
if ($has_dns_alt === true) {
return false;
}
}
// Fall back to checking the common name if we didn't get any dNSName
// alt names, as per RFC2818
if (!empty($cert['subject']['CN'])) {
// Check for a match
return (self::match_domain($host, $cert['subject']['CN']) === true);
}
return false;
}
/**
* Verify that a reference name is valid
*
* Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
* - Wildcards can only occur in a name with more than 3 components
* - Wildcards can only occur as the last character in the first
* component
* - Wildcards may be preceded by additional characters
*
* We modify these rules to be a bit stricter and only allow the wildcard
* character to be the full first component; that is, with the exclusion of
* the third rule.
*
* @param string|Stringable $reference Reference dNSName
* @return boolean Is the name valid?
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
*/
public static function verify_reference_name($reference) {
if (InputValidator::is_string_or_stringable($reference) === false) {
throw InvalidArgument::create(1, '$reference', 'string|Stringable', gettype($reference));
}
if ($reference === '') {
return false;
}
if (preg_match('`\s`', $reference) > 0) {
// Whitespace detected. This can never be a dNSName.
return false;
}
$parts = explode('.', $reference);
if ($parts !== array_filter($parts)) {
// DNSName cannot contain two dots next to each other.
return false;
}
// Check the first part of the name
$first = array_shift($parts);
if (strpos($first, '*') !== false) {
// Check that the wildcard is the full part
if ($first !== '*') {
return false;
}
// Check that we have at least 3 components (including first)
if (count($parts) < 2) {
return false;
}
}
// Check the remaining parts
foreach ($parts as $part) {
if (strpos($part, '*') !== false) {
return false;
}
}
// Nothing found, verified!
return true;
}
/**
* Match a hostname against a dNSName reference
*
* @param string|Stringable $host Requested host
* @param string|Stringable $reference dNSName to match against
* @return boolean Does the domain match?
* @throws \WpOrg\Requests\Exception\InvalidArgument When either of the passed arguments is not a string or a stringable object.
*/
public static function match_domain($host, $reference) {
if (InputValidator::is_string_or_stringable($host) === false) {
throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host));
}
// Check if the reference is blocklisted first
if (self::verify_reference_name($reference) !== true) {
return false;
}
// Check for a direct match
if ((string) $host === (string) $reference) {
return true;
}
// Calculate the valid wildcard match if the host is not an IP address
// Also validates that the host has 3 parts or more, as per Firefox's ruleset,
// as a wildcard reference is only allowed with 3 parts or more, so the
// comparison will never match if host doesn't contain 3 parts or more as well.
if (ip2long($host) === false) {
$parts = explode('.', $host);
$parts[0] = '*';
$wildcard = implode('.', $parts);
if ($wildcard === (string) $reference) {
return true;
}
}
return false;
}
}
<?php
/**
* Cookie holder object
*
* @package Requests\Cookies
*/
namespace WpOrg\Requests\Cookie;
use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;
use ReturnTypeWillChange;
use WpOrg\Requests\Cookie;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\HookManager;
use WpOrg\Requests\Iri;
use WpOrg\Requests\Response;
/**
* Cookie holder object
*
* @package Requests\Cookies
*/
class Jar implements ArrayAccess, IteratorAggregate {
/**
* Actual item data
*
* @var array
*/
protected $cookies = [];
/**
* Create a new jar
*
* @param array $cookies Existing cookie values
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array.
*/
public function __construct($cookies = []) {
if (is_array($cookies) === false) {
throw InvalidArgument::create(1, '$cookies', 'array', gettype($cookies));
}
$this->cookies = $cookies;
}
/**
* Normalise cookie data into a \WpOrg\Requests\Cookie
*
* @param string|\WpOrg\Requests\Cookie $cookie Cookie header value, possibly pre-parsed (object).
* @param string $key Optional. The name for this cookie.
* @return \WpOrg\Requests\Cookie
*/
public function normalize_cookie($cookie, $key = '') {
if ($cookie instanceof Cookie) {
return $cookie;
}
return Cookie::parse($cookie, $key);
}
/**
* Check if the given item exists
*
* @param string $offset Item key
* @return boolean Does the item exist?
*/
#[ReturnTypeWillChange]
public function offsetExists($offset) {
return isset($this->cookies[$offset]);
}
/**
* Get the value for the item
*
* @param string $offset Item key
* @return string|null Item value (null if offsetExists is false)
*/
#[ReturnTypeWillChange]
public function offsetGet($offset) {
if (!isset($this->cookies[$offset])) {
return null;
}
return $this->cookies[$offset];
}
/**
* Set the given item
*
* @param string $offset Item name
* @param string $value Item value
*
* @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value) {
if ($offset === null) {
throw new Exception('Object is a dictionary, not a list', 'invalidset');
}
$this->cookies[$offset] = $value;
}
/**
* Unset the given header
*
* @param string $offset The key for the item to unset.
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset) {
unset($this->cookies[$offset]);
}
/**
* Get an iterator for the data
*
* @return \ArrayIterator
*/
#[ReturnTypeWillChange]
public function getIterator() {
return new ArrayIterator($this->cookies);
}
/**
* Register the cookie handler with the request's hooking system
*
* @param \WpOrg\Requests\HookManager $hooks Hooking system
*/
public function register(HookManager $hooks) {
$hooks->register('requests.before_request', [$this, 'before_request']);
$hooks->register('requests.before_redirect_check', [$this, 'before_redirect_check']);
}
/**
* Add Cookie header to a request if we have any
*
* As per RFC 6265, cookies are separated by '; '
*
* @param string $url
* @param array $headers
* @param array $data
* @param string $type
* @param array $options
*/
public function before_request($url, &$headers, &$data, &$type, &$options) {
if (!$url instanceof Iri) {
$url = new Iri($url);
}
if (!empty($this->cookies)) {
$cookies = [];
foreach ($this->cookies as $key => $cookie) {
$cookie = $this->normalize_cookie($cookie, $key);
// Skip expired cookies
if ($cookie->is_expired()) {
continue;
}
if ($cookie->domain_matches($url->host)) {
$cookies[] = $cookie->format_for_header();
}
}
$headers['Cookie'] = implode('; ', $cookies);
}
}
/**
* Parse all cookies from a response and attach them to the response
*
* @param \WpOrg\Requests\Response $response Response as received.
*/
public function before_redirect_check(Response $response) {
$url = $response->url;
if (!$url instanceof Iri) {
$url = new Iri($url);
}
$cookies = Cookie::parse_from_headers($response->headers, $url);
$this->cookies = array_merge($this->cookies, $cookies);
$response->cookies = $this;
}
}
<?php
/**
* Handles adding and dispatching events
*
* @package Requests\EventDispatcher
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\HookManager;
use WpOrg\Requests\Utility\InputValidator;
/**
* Handles adding and dispatching events
*
* @package Requests\EventDispatcher
*/
class Hooks implements HookManager {
/**
* Registered callbacks for each hook
*
* @var array
*/
protected $hooks = [];
/**
* Register a callback for a hook
*
* @param string $hook Hook name
* @param callable $callback Function/method to call on event
* @param int $priority Priority number. <0 is executed earlier, >0 is executed later
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $callback argument is not callable.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $priority argument is not an integer.
*/
public function register($hook, $callback, $priority = 0) {
if (is_string($hook) === false) {
throw InvalidArgument::create(1, '$hook', 'string', gettype($hook));
}
if (is_callable($callback) === false) {
throw InvalidArgument::create(2, '$callback', 'callable', gettype($callback));
}
if (InputValidator::is_numeric_array_key($priority) === false) {
throw InvalidArgument::create(3, '$priority', 'integer', gettype($priority));
}
if (!isset($this->hooks[$hook])) {
$this->hooks[$hook] = [
$priority => [],
];
} elseif (!isset($this->hooks[$hook][$priority])) {
$this->hooks[$hook][$priority] = [];
}
$this->hooks[$hook][$priority][] = $callback;
}
/**
* Dispatch a message
*
* @param string $hook Hook name
* @param array $parameters Parameters to pass to callbacks
* @return boolean Successfulness
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string.
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $parameters argument is not an array.
*/
public function dispatch($hook, $parameters = []) {
if (is_string($hook) === false) {
throw InvalidArgument::create(1, '$hook', 'string', gettype($hook));
}
// Check strictly against array, as Array* objects don't work in combination with `call_user_func_array()`.
if (is_array($parameters) === false) {
throw InvalidArgument::create(2, '$parameters', 'array', gettype($parameters));
}
if (empty($this->hooks[$hook])) {
return false;
}
if (!empty($parameters)) {
// Strip potential keys from the array to prevent them being interpreted as parameter names in PHP 8.0.
$parameters = array_values($parameters);
}
ksort($this->hooks[$hook]);
foreach ($this->hooks[$hook] as $priority => $hooked) {
foreach ($hooked as $callback) {
$callback(...$parameters);
}
}
return true;
}
public function __wakeup() {
throw new \LogicException( __CLASS__ . ' should never be unserialized' );
}
}
<?php
/**
* Capability interface declaring the known capabilities.
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests;
/**
* Capability interface declaring the known capabilities.
*
* This is used as the authoritative source for which capabilities can be queried.
*
* @package Requests\Utilities
*/
interface Capability {
/**
* Support for SSL.
*
* @var string
*/
const SSL = 'ssl';
/**
* Collection of all capabilities supported in Requests.
*
* Note: this does not automatically mean that the capability will be supported for your chosen transport!
*
* @var string[]
*/
const ALL = [
self::SSL,
];
}
<?php
namespace WpOrg\Requests;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;
/**
* IDNA URL encoder
*
* Note: Not fully compliant, as nameprep does nothing yet.
*
* @package Requests\Utilities
*
* @link https://tools.ietf.org/html/rfc3490 IDNA specification
* @link https://tools.ietf.org/html/rfc3492 Punycode/Bootstrap specification
*/
class IdnaEncoder {
/**
* ACE prefix used for IDNA
*
* @link https://tools.ietf.org/html/rfc3490#section-5
* @var string
*/
const ACE_PREFIX = 'xn--';
/**
* Maximum length of a IDNA URL in ASCII.
*
* @see \WpOrg\Requests\IdnaEncoder::to_ascii()
*
* @since 2.0.0
*
* @var int
*/
const MAX_LENGTH = 64;
/**#@+
* Bootstrap constant for Punycode
*
* @link https://tools.ietf.org/html/rfc3492#section-5
* @var int
*/
const BOOTSTRAP_BASE = 36;
const BOOTSTRAP_TMIN = 1;
const BOOTSTRAP_TMAX = 26;
const BOOTSTRAP_SKEW = 38;
const BOOTSTRAP_DAMP = 700;
const BOOTSTRAP_INITIAL_BIAS = 72;
const BOOTSTRAP_INITIAL_N = 128;
/**#@-*/
/**
* Encode a hostname using Punycode
*
* @param string|Stringable $hostname Hostname
* @return string Punycode-encoded hostname
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
*/
public static function encode($hostname) {
if (InputValidator::is_string_or_stringable($hostname) === false) {
throw InvalidArgument::create(1, '$hostname', 'string|Stringable', gettype($hostname));
}
$parts = explode('.', $hostname);
foreach ($parts as &$part) {
$part = self::to_ascii($part);
}
return implode('.', $parts);
}
/**
* Convert a UTF-8 text string to an ASCII string using Punycode
*
* @param string $text ASCII or UTF-8 string (max length 64 characters)
* @return string ASCII string
*
* @throws \WpOrg\Requests\Exception Provided string longer than 64 ASCII characters (`idna.provided_too_long`)
* @throws \WpOrg\Requests\Exception Prepared string longer than 64 ASCII characters (`idna.prepared_too_long`)
* @throws \WpOrg\Requests\Exception Provided string already begins with xn-- (`idna.provided_is_prefixed`)
* @throws \WpOrg\Requests\Exception Encoded string longer than 64 ASCII characters (`idna.encoded_too_long`)
*/
public static function to_ascii($text) {
// Step 1: Check if the text is already ASCII
if (self::is_ascii($text)) {
// Skip to step 7
if (strlen($text) < self::MAX_LENGTH) {
return $text;
}
throw new Exception('Provided string is too long', 'idna.provided_too_long', $text);
}
// Step 2: nameprep
$text = self::nameprep($text);
// Step 3: UseSTD3ASCIIRules is false, continue
// Step 4: Check if it's ASCII now
if (self::is_ascii($text)) {
// Skip to step 7
/*
* As the `nameprep()` method returns the original string, this code will never be reached until
* that method is properly implemented.
*/
// @codeCoverageIgnoreStart
if (strlen($text) < self::MAX_LENGTH) {
return $text;
}
throw new Exception('Prepared string is too long', 'idna.prepared_too_long', $text);
// @codeCoverageIgnoreEnd
}
// Step 5: Check ACE prefix
if (strpos($text, self::ACE_PREFIX) === 0) {
throw new Exception('Provided string begins with ACE prefix', 'idna.provided_is_prefixed', $text);
}
// Step 6: Encode with Punycode
$text = self::punycode_encode($text);
// Step 7: Prepend ACE prefix
$text = self::ACE_PREFIX . $text;
// Step 8: Check size
if (strlen($text) < self::MAX_LENGTH) {
return $text;
}
throw new Exception('Encoded string is too long', 'idna.encoded_too_long', $text);
}
/**
* Check whether a given text string contains only ASCII characters
*
* @internal (Testing found regex was the fastest implementation)
*
* @param string $text Text to examine.
* @return bool Is the text string ASCII-only?
*/
protected static function is_ascii($text) {
return (preg_match('/(?:[^\x00-\x7F])/', $text) !== 1);
}
/**
* Prepare a text string for use as an IDNA name
*
* @todo Implement this based on RFC 3491 and the newer 5891
* @param string $text Text to prepare.
* @return string Prepared string
*/
protected static function nameprep($text) {
return $text;
}
/**
* Convert a UTF-8 string to a UCS-4 codepoint array
*
* Based on \WpOrg\Requests\Iri::replace_invalid_with_pct_encoding()
*
* @param string $input Text to convert.
* @return array Unicode code points
*
* @throws \WpOrg\Requests\Exception Invalid UTF-8 codepoint (`idna.invalidcodepoint`)
*/
protected static function utf8_to_codepoints($input) {
$codepoints = [];
// Get number of bytes
$strlen = strlen($input);
// phpcs:ignore Generic.CodeAnalysis.JumbledIncrementer -- This is a deliberate choice.
for ($position = 0; $position < $strlen; $position++) {
$value = ord($input[$position]);
if ((~$value & 0x80) === 0x80) { // One byte sequence:
$character = $value;
$length = 1;
$remaining = 0;
} elseif (($value & 0xE0) === 0xC0) { // Two byte sequence:
$character = ($value & 0x1F) << 6;
$length = 2;
$remaining = 1;
} elseif (($value & 0xF0) === 0xE0) { // Three byte sequence:
$character = ($value & 0x0F) << 12;
$length = 3;
$remaining = 2;
} elseif (($value & 0xF8) === 0xF0) { // Four byte sequence:
$character = ($value & 0x07) << 18;
$length = 4;
$remaining = 3;
} else { // Invalid byte:
throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $value);
}
if ($remaining > 0) {
if ($position + $length > $strlen) {
throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
}
for ($position++; $remaining > 0; $position++) {
$value = ord($input[$position]);
// If it is invalid, count the sequence as invalid and reprocess the current byte:
if (($value & 0xC0) !== 0x80) {
throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
}
--$remaining;
$character |= ($value & 0x3F) << ($remaining * 6);
}
$position--;
}
if (// Non-shortest form sequences are invalid
$length > 1 && $character <= 0x7F
|| $length > 2 && $character <= 0x7FF
|| $length > 3 && $character <= 0xFFFF
// Outside of range of ucschar codepoints
// Noncharacters
|| ($character & 0xFFFE) === 0xFFFE
|| $character >= 0xFDD0 && $character <= 0xFDEF
|| (
// Everything else not in ucschar
$character > 0xD7FF && $character < 0xF900
|| $character < 0x20
|| $character > 0x7E && $character < 0xA0
|| $character > 0xEFFFD
)
) {
throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
}
$codepoints[] = $character;
}
return $codepoints;
}
/**
* RFC3492-compliant encoder
*
* @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code
*
* @param string $input UTF-8 encoded string to encode
* @return string Punycode-encoded string
*
* @throws \WpOrg\Requests\Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`)
*/
public static function punycode_encode($input) {
$output = '';
// let n = initial_n
$n = self::BOOTSTRAP_INITIAL_N;
// let delta = 0
$delta = 0;
// let bias = initial_bias
$bias = self::BOOTSTRAP_INITIAL_BIAS;
// let h = b = the number of basic code points in the input
$h = 0;
$b = 0; // see loop
// copy them to the output in order
$codepoints = self::utf8_to_codepoints($input);
$extended = [];
foreach ($codepoints as $char) {
if ($char < 128) {
// Character is valid ASCII
// TODO: this should also check if it's valid for a URL
$output .= chr($char);
$h++;
// Check if the character is non-ASCII, but below initial n
// This never occurs for Punycode, so ignore in coverage
// @codeCoverageIgnoreStart
} elseif ($char < $n) {
throw new Exception('Invalid character', 'idna.character_outside_domain', $char);
// @codeCoverageIgnoreEnd
} else {
$extended[$char] = true;
}
}
$extended = array_keys($extended);
sort($extended);
$b = $h;
// [copy them] followed by a delimiter if b > 0
if (strlen($output) > 0) {
$output .= '-';
}
// {if the input contains a non-basic code point < n then fail}
// while h < length(input) do begin
$codepointcount = count($codepoints);
while ($h < $codepointcount) {
// let m = the minimum code point >= n in the input
$m = array_shift($extended);
//printf('next code point to insert is %s' . PHP_EOL, dechex($m));
// let delta = delta + (m - n) * (h + 1), fail on overflow
$delta += ($m - $n) * ($h + 1);
// let n = m
$n = $m;
// for each code point c in the input (in order) do begin
for ($num = 0; $num < $codepointcount; $num++) {
$c = $codepoints[$num];
// if c < n then increment delta, fail on overflow
if ($c < $n) {
$delta++;
} elseif ($c === $n) { // if c == n then begin
// let q = delta
$q = $delta;
// for k = base to infinity in steps of base do begin
for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) {
// let t = tmin if k <= bias {+ tmin}, or
// tmax if k >= bias + tmax, or k - bias otherwise
if ($k <= ($bias + self::BOOTSTRAP_TMIN)) {
$t = self::BOOTSTRAP_TMIN;
} elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) {
$t = self::BOOTSTRAP_TMAX;
} else {
$t = $k - $bias;
}
// if q < t then break
if ($q < $t) {
break;
}
// output the code point for digit t + ((q - t) mod (base - t))
$digit = (int) ($t + (($q - $t) % (self::BOOTSTRAP_BASE - $t)));
$output .= self::digit_to_char($digit);
// let q = (q - t) div (base - t)
$q = (int) floor(($q - $t) / (self::BOOTSTRAP_BASE - $t));
} // end
// output the code point for digit q
$output .= self::digit_to_char($q);
// let bias = adapt(delta, h + 1, test h equals b?)
$bias = self::adapt($delta, $h + 1, $h === $b);
// let delta = 0
$delta = 0;
// increment h
$h++;
} // end
} // end
// increment delta and n
$delta++;
$n++;
} // end
return $output;
}
/**
* Convert a digit to its respective character
*
* @link https://tools.ietf.org/html/rfc3492#section-5
*
* @param int $digit Digit in the range 0-35
* @return string Single character corresponding to digit
*
* @throws \WpOrg\Requests\Exception On invalid digit (`idna.invalid_digit`)
*/
protected static function digit_to_char($digit) {
// @codeCoverageIgnoreStart
// As far as I know, this never happens, but still good to be sure.
if ($digit < 0 || $digit > 35) {
throw new Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit);
}
// @codeCoverageIgnoreEnd
$digits = 'abcdefghijklmnopqrstuvwxyz0123456789';
return substr($digits, $digit, 1);
}
/**
* Adapt the bias
*
* @link https://tools.ietf.org/html/rfc3492#section-6.1
* @param int $delta
* @param int $numpoints
* @param bool $firsttime
* @return int|float New bias
*
* function adapt(delta,numpoints,firsttime):
*/
protected static function adapt($delta, $numpoints, $firsttime) {
// if firsttime then let delta = delta div damp
if ($firsttime) {
$delta = floor($delta / self::BOOTSTRAP_DAMP);
} else {
// else let delta = delta div 2
$delta = floor($delta / 2);
}
// let delta = delta + (delta div numpoints)
$delta += floor($delta / $numpoints);
// let k = 0
$k = 0;
// while delta > ((base - tmin) * tmax) div 2 do begin
$max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2);
while ($delta > $max) {
// let delta = delta div (base - tmin)
$delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN));
// let k = k + base
$k += self::BOOTSTRAP_BASE;
} // end
// return k + (((base - tmin + 1) * delta) div (delta + skew))
return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW));
}
}
<?php
/**
* Event dispatcher
*
* @package Requests\EventDispatcher
*/
namespace WpOrg\Requests;
/**
* Event dispatcher
*
* @package Requests\EventDispatcher
*/
interface HookManager {
/**
* Register a callback for a hook
*
* @param string $hook Hook name
* @param callable $callback Function/method to call on event
* @param int $priority Priority number. <0 is executed earlier, >0 is executed later
*/
public function register($hook, $callback, $priority = 0);
/**
* Dispatch a message
*
* @param string $hook Hook name
* @param array $parameters Parameters to pass to callbacks
* @return boolean Successfulness
*/
public function dispatch($hook, $parameters = []);
}
<?php
/**
* Base HTTP transport
*
* @package Requests\Transport
*/
namespace WpOrg\Requests;
/**
* Base HTTP transport
*
* @package Requests\Transport
*/
interface Transport {
/**
* Perform a request
*
* @param string $url URL to request
* @param array $headers Associative array of request headers
* @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
* @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
* @return string Raw HTTP result
*/
public function request($url, $headers = [], $data = [], $options = []);
/**
* Send multiple requests simultaneously
*
* @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see \WpOrg\Requests\Transport::request()}
* @param array $options Global options, see {@see \WpOrg\Requests\Requests::response()} for documentation
* @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
*/
public function request_multiple($requests, $options);
/**
* Self-test whether the transport can be used.
*
* The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
*
* @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
* @return bool Whether the transport can be used.
*/
public static function test($capabilities = []);
}
<?php
/**
* Autoloader for Requests for PHP.
*
* Include this file if you'd like to avoid having to create your own autoloader.
*
* @package Requests
* @since 2.0.0
*
* @codeCoverageIgnore
*/
namespace WpOrg\Requests;
/*
* Ensure the autoloader is only declared once.
* This safeguard is in place as this is the typical entry point for this library
* and this file being required unconditionally could easily cause
* fatal "Class already declared" errors.
*/
if (class_exists('WpOrg\Requests\Autoload') === false) {
/**
* Autoloader for Requests for PHP.
*
* This autoloader supports the PSR-4 based Requests 2.0.0 classes in a case-sensitive manner
* as the most common server OS-es are case-sensitive and the file names are in mixed case.
*
* For the PSR-0 Requests 1.x BC-layer, requested classes will be treated case-insensitively.
*
* @package Requests
*/
final class Autoload {
/**
* List of the old PSR-0 class names in lowercase as keys with their PSR-4 case-sensitive name as a value.
*
* @var array
*/
private static $deprecated_classes = [
// Interfaces.
'requests_auth' => '\WpOrg\Requests\Auth',
'requests_hooker' => '\WpOrg\Requests\HookManager',
'requests_proxy' => '\WpOrg\Requests\Proxy',
'requests_transport' => '\WpOrg\Requests\Transport',
// Classes.
'requests_cookie' => '\WpOrg\Requests\Cookie',
'requests_exception' => '\WpOrg\Requests\Exception',
'requests_hooks' => '\WpOrg\Requests\Hooks',
'requests_idnaencoder' => '\WpOrg\Requests\IdnaEncoder',
'requests_ipv6' => '\WpOrg\Requests\Ipv6',
'requests_iri' => '\WpOrg\Requests\Iri',
'requests_response' => '\WpOrg\Requests\Response',
'requests_session' => '\WpOrg\Requests\Session',
'requests_ssl' => '\WpOrg\Requests\Ssl',
'requests_auth_basic' => '\WpOrg\Requests\Auth\Basic',
'requests_cookie_jar' => '\WpOrg\Requests\Cookie\Jar',
'requests_proxy_http' => '\WpOrg\Requests\Proxy\Http',
'requests_response_headers' => '\WpOrg\Requests\Response\Headers',
'requests_transport_curl' => '\WpOrg\Requests\Transport\Curl',
'requests_transport_fsockopen' => '\WpOrg\Requests\Transport\Fsockopen',
'requests_utility_caseinsensitivedictionary' => '\WpOrg\Requests\Utility\CaseInsensitiveDictionary',
'requests_utility_filterediterator' => '\WpOrg\Requests\Utility\FilteredIterator',
'requests_exception_http' => '\WpOrg\Requests\Exception\Http',
'requests_exception_transport' => '\WpOrg\Requests\Exception\Transport',
'requests_exception_transport_curl' => '\WpOrg\Requests\Exception\Transport\Curl',
'requests_exception_http_304' => '\WpOrg\Requests\Exception\Http\Status304',
'requests_exception_http_305' => '\WpOrg\Requests\Exception\Http\Status305',
'requests_exception_http_306' => '\WpOrg\Requests\Exception\Http\Status306',
'requests_exception_http_400' => '\WpOrg\Requests\Exception\Http\Status400',
'requests_exception_http_401' => '\WpOrg\Requests\Exception\Http\Status401',
'requests_exception_http_402' => '\WpOrg\Requests\Exception\Http\Status402',
'requests_exception_http_403' => '\WpOrg\Requests\Exception\Http\Status403',
'requests_exception_http_404' => '\WpOrg\Requests\Exception\Http\Status404',
'requests_exception_http_405' => '\WpOrg\Requests\Exception\Http\Status405',
'requests_exception_http_406' => '\WpOrg\Requests\Exception\Http\Status406',
'requests_exception_http_407' => '\WpOrg\Requests\Exception\Http\Status407',
'requests_exception_http_408' => '\WpOrg\Requests\Exception\Http\Status408',
'requests_exception_http_409' => '\WpOrg\Requests\Exception\Http\Status409',
'requests_exception_http_410' => '\WpOrg\Requests\Exception\Http\Status410',
'requests_exception_http_411' => '\WpOrg\Requests\Exception\Http\Status411',
'requests_exception_http_412' => '\WpOrg\Requests\Exception\Http\Status412',
'requests_exception_http_413' => '\WpOrg\Requests\Exception\Http\Status413',
'requests_exception_http_414' => '\WpOrg\Requests\Exception\Http\Status414',
'requests_exception_http_415' => '\WpOrg\Requests\Exception\Http\Status415',
'requests_exception_http_416' => '\WpOrg\Requests\Exception\Http\Status416',
'requests_exception_http_417' => '\WpOrg\Requests\Exception\Http\Status417',
'requests_exception_http_418' => '\WpOrg\Requests\Exception\Http\Status418',
'requests_exception_http_428' => '\WpOrg\Requests\Exception\Http\Status428',
'requests_exception_http_429' => '\WpOrg\Requests\Exception\Http\Status429',
'requests_exception_http_431' => '\WpOrg\Requests\Exception\Http\Status431',
'requests_exception_http_500' => '\WpOrg\Requests\Exception\Http\Status500',
'requests_exception_http_501' => '\WpOrg\Requests\Exception\Http\Status501',
'requests_exception_http_502' => '\WpOrg\Requests\Exception\Http\Status502',
'requests_exception_http_503' => '\WpOrg\Requests\Exception\Http\Status503',
'requests_exception_http_504' => '\WpOrg\Requests\Exception\Http\Status504',
'requests_exception_http_505' => '\WpOrg\Requests\Exception\Http\Status505',
'requests_exception_http_511' => '\WpOrg\Requests\Exception\Http\Status511',
'requests_exception_http_unknown' => '\WpOrg\Requests\Exception\Http\StatusUnknown',
];
/**
* Register the autoloader.
*
* Note: the autoloader is *prepended* in the autoload queue.
* This is done to ensure that the Requests 2.0 autoloader takes precedence
* over a potentially (dependency-registered) Requests 1.x autoloader.
*
* @internal This method contains a safeguard against the autoloader being
* registered multiple times. This safeguard uses a global constant to
* (hopefully/in most cases) still function correctly, even if the
* class would be renamed.
*
* @return void
*/
public static function register() {
if (defined('REQUESTS_AUTOLOAD_REGISTERED') === false) {
spl_autoload_register([self::class, 'load'], true);
define('REQUESTS_AUTOLOAD_REGISTERED', true);
}
}
/**
* Autoloader.
*
* @param string $class_name Name of the class name to load.
*
* @return bool Whether a class was loaded or not.
*/
public static function load($class_name) {
// Check that the class starts with "Requests" (PSR-0) or "WpOrg\Requests" (PSR-4).
$psr_4_prefix_pos = strpos($class_name, 'WpOrg\\Requests\\');
if (stripos($class_name, 'Requests') !== 0 && $psr_4_prefix_pos !== 0) {
return false;
}
$class_lower = strtolower($class_name);
if ($class_lower === 'requests') {
// Reference to the original PSR-0 Requests class.
$file = dirname(__DIR__) . '/library/Requests.php';
} elseif ($psr_4_prefix_pos === 0) {
// PSR-4 classname.
$file = __DIR__ . '/' . strtr(substr($class_name, 15), '\\', '/') . '.php';
}
if (isset($file) && file_exists($file)) {
include $file;
return true;
}
/*
* Okay, so the class starts with "Requests", but we couldn't find the file.
* If this is one of the deprecated/renamed PSR-0 classes being requested,
* let's alias it to the new name and throw a deprecation notice.
*/
if (isset(self::$deprecated_classes[$class_lower])) {
/*
* Integrators who cannot yet upgrade to the PSR-4 class names can silence deprecations
* by defining a `REQUESTS_SILENCE_PSR0_DEPRECATIONS` constant and setting it to `true`.
* The constant needs to be defined before the first deprecated class is requested
* via this autoloader.
*/
if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS') || REQUESTS_SILENCE_PSR0_DEPRECATIONS !== true) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
trigger_error(
'The PSR-0 `Requests_...` class names in the Requests library are deprecated.'
. ' Switch to the PSR-4 `WpOrg\Requests\...` class names at your earliest convenience.',
E_USER_DEPRECATED
);
// Prevent the deprecation notice from being thrown twice.
if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS')) {
define('REQUESTS_SILENCE_PSR0_DEPRECATIONS', true);
}
}
// Create an alias and let the autoloader recursively kick in to load the PSR-4 class.
return class_alias(self::$deprecated_classes[$class_lower], $class_name, true);
}
return false;
}
}
}
<?php
/**
* HTTP response class
*
* Contains a response from \WpOrg\Requests\Requests::request()
*
* @package Requests
*/
namespace WpOrg\Requests;
use WpOrg\Requests\Cookie\Jar;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Response\Headers;
/**
* HTTP response class
*
* Contains a response from \WpOrg\Requests\Requests::request()
*
* @package Requests
*/
class Response {
/**
* Response body
*
* @var string
*/
public $body = '';
/**
* Raw HTTP data from the transport
*
* @var string
*/
public $raw = '';
/**
* Headers, as an associative array
*
* @var \WpOrg\Requests\Response\Headers Array-like object representing headers
*/
public $headers = [];
/**
* Status code, false if non-blocking
*
* @var integer|boolean
*/
public $status_code = false;
/**
* Protocol version, false if non-blocking
*
* @var float|boolean
*/
public $protocol_version = false;
/**
* Whether the request succeeded or not
*
* @var boolean
*/
public $success = false;
/**
* Number of redirects the request used
*
* @var integer
*/
public $redirects = 0;
/**
* URL requested
*
* @var string
*/
public $url = '';
/**
* Previous requests (from redirects)
*
* @var array Array of \WpOrg\Requests\Response objects
*/
public $history = [];
/**
* Cookies from the request
*
* @var \WpOrg\Requests\Cookie\Jar Array-like object representing a cookie jar
*/
public $cookies = [];
/**
* Constructor
*/
public function __construct() {
$this->headers = new Headers();
$this->cookies = new Jar();
}
/**
* Is the response a redirect?
*
* @return boolean True if redirect (3xx status), false if not.
*/
public function is_redirect() {
$code = $this->status_code;
return in_array($code, [300, 301, 302, 303, 307], true) || $code > 307 && $code < 400;
}
/**
* Throws an exception if the request was not successful
*
* @param boolean $allow_redirects Set to false to throw on a 3xx as well
*
* @throws \WpOrg\Requests\Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
* @throws \WpOrg\Requests\Exception\Http On non-successful status code. Exception class corresponds to "Status" + code (e.g. {@see \WpOrg\Requests\Exception\Http\Status404})
*/
public function throw_for_status($allow_redirects = true) {
if ($this->is_redirect()) {
if ($allow_redirects !== true) {
throw new Exception('Redirection not allowed', 'response.no_redirects', $this);
}
} elseif (!$this->success) {
$exception = Http::get_class($this->status_code);
throw new $exception(null, $this);
}
}
/**
* JSON decode the response body.
*
* The method parameters are the same as those for the PHP native `json_decode()` function.
*
* @link https://php.net/json-decode
*
* @param bool|null $associative Optional. When `true`, JSON objects will be returned as associative arrays;
* When `false`, JSON objects will be returned as objects.
* When `null`, JSON objects will be returned as associative arrays
* or objects depending on whether `JSON_OBJECT_AS_ARRAY` is set in the flags.
* Defaults to `true` (in contrast to the PHP native default of `null`).
* @param int $depth Optional. Maximum nesting depth of the structure being decoded.
* Defaults to `512`.
* @param int $options Optional. Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE,
* JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY, JSON_THROW_ON_ERROR.
* Defaults to `0` (no options set).
*
* @return array
*
* @throws \WpOrg\Requests\Exception If `$this->body` is not valid json.
*/
public function decode_body($associative = true, $depth = 512, $options = 0) {
$data = json_decode($this->body, $associative, $depth, $options);
if (json_last_error() !== JSON_ERROR_NONE) {
$last_error = json_last_error_msg();
throw new Exception('Unable to parse JSON data: ' . $last_error, 'response.invalid', $this);
}
return $data;
}
}
<?php
/**
* Case-insensitive dictionary, suitable for HTTP headers
*
* @package Requests
*/
namespace WpOrg\Requests\Response;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
use WpOrg\Requests\Utility\FilteredIterator;
/**
* Case-insensitive dictionary, suitable for HTTP headers
*
* @package Requests
*/
class Headers extends CaseInsensitiveDictionary {
/**
* Get the given header
*
* Unlike {@see \WpOrg\Requests\Response\Headers::getValues()}, this returns a string. If there are
* multiple values, it concatenates them with a comma as per RFC2616.
*
* Avoid using this where commas may be used unquoted in values, such as
* Set-Cookie headers.
*
* @param string $offset Name of the header to retrieve.
* @return string|null Header value
*/
public function offsetGet($offset) {
if (is_string($offset)) {
$offset = strtolower($offset);
}
if (!isset($this->data[$offset])) {
return null;
}
return $this->flatten($this->data[$offset]);
}
/**
* Set the given item
*
* @param string $offset Item name
* @param string $value Item value
*
* @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
*/
public function offsetSet($offset, $value) {
if ($offset === null) {
throw new Exception('Object is a dictionary, not a list', 'invalidset');
}
if (is_string($offset)) {
$offset = strtolower($offset);
}
if (!isset($this->data[$offset])) {
$this->data[$offset] = [];
}
$this->data[$offset][] = $value;
}
/**
* Get all values for a given header
*
* @param string $offset Name of the header to retrieve.
* @return array|null Header values
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not valid as an array key.
*/
public function getValues($offset) {
if (!is_string($offset) && !is_int($offset)) {
throw InvalidArgument::create(1, '$offset', 'string|int', gettype($offset));
}
if (is_string($offset)) {
$offset = strtolower($offset);
}
if (!isset($this->data[$offset])) {
return null;
}
return $this->data[$offset];
}
/**
* Flattens a value into a string
*
* Converts an array into a string by imploding values with a comma, as per
* RFC2616's rules for folding headers.
*
* @param string|array $value Value to flatten
* @return string Flattened value
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or an array.
*/
public function flatten($value) {
if (is_string($value)) {
return $value;
}
if (is_array($value)) {
return implode(',', $value);
}
throw InvalidArgument::create(1, '$value', 'string|array', gettype($value));
}
/**
* Get an iterator for the data
*
* Converts the internally stored values to a comma-separated string if there is more
* than one value for a key.
*
* @return \ArrayIterator
*/
public function getIterator() {
return new FilteredIterator($this->data, [$this, 'flatten']);
}
}
[02-Dec-2025 10:42:21 America/Bogota] PHP Fatal error: Uncaught Error: Class "WpOrg\Requests\Utility\CaseInsensitiveDictionary" not found in /home/coopserp/public_html/wp-includes/Requests/src/Response/Headers.php:20
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/Requests/src/Response/Headers.php on line 20
<?php
/**
* Input validation utilities.
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests\Utility;
use ArrayAccess;
use CurlHandle;
use Traversable;
/**
* Input validation utilities.
*
* @package Requests\Utilities
*/
final class InputValidator {
/**
* Verify that a received input parameter is of type string or is "stringable".
*
* @param mixed $input Input parameter to verify.
*
* @return bool
*/
public static function is_string_or_stringable($input) {
return is_string($input) || self::is_stringable_object($input);
}
/**
* Verify whether a received input parameter is usable as an integer array key.
*
* @param mixed $input Input parameter to verify.
*
* @return bool
*/
public static function is_numeric_array_key($input) {
if (is_int($input)) {
return true;
}
if (!is_string($input)) {
return false;
}
return (bool) preg_match('`^-?[0-9]+$`', $input);
}
/**
* Verify whether a received input parameter is "stringable".
*
* @param mixed $input Input parameter to verify.
*
* @return bool
*/
public static function is_stringable_object($input) {
return is_object($input) && method_exists($input, '__toString');
}
/**
* Verify whether a received input parameter is _accessible as if it were an array_.
*
* @param mixed $input Input parameter to verify.
*
* @return bool
*/
public static function has_array_access($input) {
return is_array($input) || $input instanceof ArrayAccess;
}
/**
* Verify whether a received input parameter is "iterable".
*
* @internal The PHP native `is_iterable()` function was only introduced in PHP 7.1
* and this library still supports PHP 5.6.
*
* @param mixed $input Input parameter to verify.
*
* @return bool
*/
public static function is_iterable($input) {
return is_array($input) || $input instanceof Traversable;
}
/**
* Verify whether a received input parameter is a Curl handle.
*
* The PHP Curl extension worked with resources prior to PHP 8.0 and with
* an instance of the `CurlHandle` class since PHP 8.0.
* {@link https://www.php.net/manual/en/migration80.incompatible.php#migration80.incompatible.resource2object}
*
* @param mixed $input Input parameter to verify.
*
* @return bool
*/
public static function is_curl_handle($input) {
if (is_resource($input)) {
return get_resource_type($input) === 'curl';
}
if (is_object($input)) {
return $input instanceof CurlHandle;
}
return false;
}
}
<?php
/**
* Iterator for arrays requiring filtered values
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests\Utility;
use ArrayIterator;
use ReturnTypeWillChange;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;
/**
* Iterator for arrays requiring filtered values
*
* @package Requests\Utilities
*/
final class FilteredIterator extends ArrayIterator {
/**
* Callback to run as a filter
*
* @var callable
*/
private $callback;
/**
* Create a new iterator
*
* @param array $data The array or object to be iterated on.
* @param callable $callback Callback to be called on each value
*
* @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not iterable.
*/
public function __construct($data, $callback) {
if (InputValidator::is_iterable($data) === false) {
throw InvalidArgument::create(1, '$data', 'iterable', gettype($data));
}
parent::__construct($data);
if (is_callable($callback)) {
$this->callback = $callback;
}
}
/**
* Prevent unserialization of the object for security reasons.
*
* @phpcs:disable PHPCompatibility.FunctionNameRestrictions.NewMagicMethods.__unserializeFound
*
* @param array $data Restored array of data originally serialized.
*
* @return void
*/
#[ReturnTypeWillChange]
public function __unserialize($data) {}
// phpcs:enable
/**
* Perform reinitialization tasks.
*
* Prevents a callback from being injected during unserialization of an object.
*
* @return void
*/
public function __wakeup() {
unset($this->callback);
}
/**
* Get the current item's value after filtering
*
* @return string
*/
#[ReturnTypeWillChange]
public function current() {
$value = parent::current();
if (is_callable($this->callback)) {
$value = call_user_func($this->callback, $value);
}
return $value;
}
/**
* Prevent creating a PHP value from a stored representation of the object for security reasons.
*
* @param string $data The serialized string.
*
* @return void
*/
#[ReturnTypeWillChange]
public function unserialize($data) {}
}
<?php
/**
* Case-insensitive dictionary, suitable for HTTP headers
*
* @package Requests\Utilities
*/
namespace WpOrg\Requests\Utility;
use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;
use ReturnTypeWillChange;
use WpOrg\Requests\Exception;
/**
* Case-insensitive dictionary, suitable for HTTP headers
*
* @package Requests\Utilities
*/
class CaseInsensitiveDictionary implements ArrayAccess, IteratorAggregate {
/**
* Actual item data
*
* @var array
*/
protected $data = [];
/**
* Creates a case insensitive dictionary.
*
* @param array $data Dictionary/map to convert to case-insensitive
*/
public function __construct(array $data = []) {
foreach ($data as $offset => $value) {
$this->offsetSet($offset, $value);
}
}
/**
* Check if the given item exists
*
* @param string $offset Item key
* @return boolean Does the item exist?
*/
#[ReturnTypeWillChange]
public function offsetExists($offset) {
if (is_string($offset)) {
$offset = strtolower($offset);
}
return isset($this->data[$offset]);
}
/**
* Get the value for the item
*
* @param string $offset Item key
* @return string|null Item value (null if the item key doesn't exist)
*/
#[ReturnTypeWillChange]
public function offsetGet($offset) {
if (is_string($offset)) {
$offset = strtolower($offset);
}
if (!isset($this->data[$offset])) {
return null;
}
return $this->data[$offset];
}
/**
* Set the given item
*
* @param string $offset Item name
* @param string $value Item value
*
* @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value) {
if ($offset === null) {
throw new Exception('Object is a dictionary, not a list', 'invalidset');
}
if (is_string($offset)) {
$offset = strtolower($offset);
}
$this->data[$offset] = $value;
}
/**
* Unset the given header
*
* @param string $offset The key for the item to unset.
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset) {
if (is_string($offset)) {
$offset = strtolower($offset);
}
unset($this->data[$offset]);
}
/**
* Get an iterator for the data
*
* @return \ArrayIterator
*/
#[ReturnTypeWillChange]
public function getIterator() {
return new ArrayIterator($this->data);
}
/**
* Get the headers as an array
*
* @return array Header data
*/
public function getAll() {
return $this->data;
}
}
<?php
/**
* Taxonomy API: Core category-specific template tags
*
* @package WordPress
* @subpackage Template
* @since 1.2.0
*/
/**
* Retrieves category link URL.
*
* @since 1.0.0
*
* @see get_term_link()
*
* @param int|object $category Category ID or object.
* @return string Link on success, empty string if category does not exist.
*/
function get_category_link( $category ) {
if ( ! is_object( $category ) ) {
$category = (int) $category;
}
$category = get_term_link( $category );
if ( is_wp_error( $category ) ) {
return '';
}
return $category;
}
/**
* Retrieves category parents with separator.
*
* @since 1.2.0
* @since 4.8.0 The `$visited` parameter was deprecated and renamed to `$deprecated`.
*
* @param int $category_id Category ID.
* @param bool $link Optional. Whether to format with link. Default false.
* @param string $separator Optional. How to separate categories. Default '/'.
* @param bool $nicename Optional. Whether to use nice name for display. Default false.
* @param array $deprecated Not used.
* @return string|WP_Error A list of category parents on success, WP_Error on failure.
*/
function get_category_parents( $category_id, $link = false, $separator = '/', $nicename = false, $deprecated = array() ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '4.8.0' );
}
$format = $nicename ? 'slug' : 'name';
$args = array(
'separator' => $separator,
'link' => $link,
'format' => $format,
);
return get_term_parents_list( $category_id, 'category', $args );
}
/**
* Retrieves post categories.
*
* This tag may be used outside The Loop by passing a post ID as the parameter.
*
* Note: This function only returns results from the default "category" taxonomy.
* For custom taxonomies use get_the_terms().
*
* @since 0.71
*
* @param int $post_id Optional. The post ID. Defaults to current post ID.
* @return WP_Term[] Array of WP_Term objects, one for each category assigned to the post.
*/
function get_the_category( $post_id = false ) {
$categories = get_the_terms( $post_id, 'category' );
if ( ! $categories || is_wp_error( $categories ) ) {
$categories = array();
}
$categories = array_values( $categories );
foreach ( array_keys( $categories ) as $key ) {
_make_cat_compat( $categories[ $key ] );
}
/**
* Filters the array of categories to return for a post.
*
* @since 3.1.0
* @since 4.4.0 Added the `$post_id` parameter.
*
* @param WP_Term[] $categories An array of categories to return for the post.
* @param int|false $post_id The post ID.
*/
return apply_filters( 'get_the_categories', $categories, $post_id );
}
/**
* Retrieves category name based on category ID.
*
* @since 0.71
*
* @param int $cat_id Category ID.
* @return string|WP_Error Category name on success, WP_Error on failure.
*/
function get_the_category_by_ID( $cat_id ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
$cat_id = (int) $cat_id;
$category = get_term( $cat_id );
if ( is_wp_error( $category ) ) {
return $category;
}
return ( $category ) ? $category->name : '';
}
/**
* Retrieves category list for a post in either HTML list or custom format.
*
* Generally used for quick, delimited (e.g. comma-separated) lists of categories,
* as part of a post entry meta.
*
* For a more powerful, list-based function, see wp_list_categories().
*
* @since 1.5.1
*
* @see wp_list_categories()
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $separator Optional. Separator between the categories. By default, the links are placed
* in an unordered list. An empty string will result in the default behavior.
* @param string $parents Optional. How to display the parents. Accepts 'multiple', 'single', or empty.
* Default empty string.
* @param int $post_id Optional. ID of the post to retrieve categories for. Defaults to the current post.
* @return string Category list for a post.
*/
function get_the_category_list( $separator = '', $parents = '', $post_id = false ) {
global $wp_rewrite;
if ( ! is_object_in_taxonomy( get_post_type( $post_id ), 'category' ) ) {
/** This filter is documented in wp-includes/category-template.php */
return apply_filters( 'the_category', '', $separator, $parents );
}
/**
* Filters the categories before building the category list.
*
* @since 4.4.0
*
* @param WP_Term[] $categories An array of the post's categories.
* @param int|false $post_id ID of the post to retrieve categories for.
* When `false`, defaults to the current post in the loop.
*/
$categories = apply_filters( 'the_category_list', get_the_category( $post_id ), $post_id );
if ( empty( $categories ) ) {
/** This filter is documented in wp-includes/category-template.php */
return apply_filters( 'the_category', __( 'Uncategorized' ), $separator, $parents );
}
$rel = ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) ? 'rel="category tag"' : 'rel="category"';
$thelist = '';
if ( '' === $separator ) {
$thelist .= '<ul class="post-categories">';
foreach ( $categories as $category ) {
$thelist .= "\n\t<li>";
switch ( strtolower( $parents ) ) {
case 'multiple':
if ( $category->parent ) {
$thelist .= get_category_parents( $category->parent, true, $separator );
}
$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name . '</a></li>';
break;
case 'single':
$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>';
if ( $category->parent ) {
$thelist .= get_category_parents( $category->parent, false, $separator );
}
$thelist .= $category->name . '</a></li>';
break;
case '':
default:
$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name . '</a></li>';
}
}
$thelist .= '</ul>';
} else {
$i = 0;
foreach ( $categories as $category ) {
if ( 0 < $i ) {
$thelist .= $separator;
}
switch ( strtolower( $parents ) ) {
case 'multiple':
if ( $category->parent ) {
$thelist .= get_category_parents( $category->parent, true, $separator );
}
$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name . '</a>';
break;
case 'single':
$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>';
if ( $category->parent ) {
$thelist .= get_category_parents( $category->parent, false, $separator );
}
$thelist .= "$category->name</a>";
break;
case '':
default:
$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name . '</a>';
}
++$i;
}
}
/**
* Filters the category or list of categories.
*
* @since 1.2.0
*
* @param string $thelist List of categories for the current post.
* @param string $separator Separator used between the categories.
* @param string $parents How to display the category parents. Accepts 'multiple',
* 'single', or empty.
*/
return apply_filters( 'the_category', $thelist, $separator, $parents );
}
/**
* Checks if the current post is within any of the given categories.
*
* The given categories are checked against the post's categories' term_ids, names and slugs.
* Categories given as integers will only be checked against the post's categories' term_ids.
*
* Prior to v2.5 of WordPress, category names were not supported.
* Prior to v2.7, category slugs were not supported.
* Prior to v2.7, only one category could be compared: in_category( $single_category ).
* Prior to v2.7, this function could only be used in the WordPress Loop.
* As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 1.2.0
* @since 2.7.0 The `$post` parameter was added.
*
* @param int|string|int[]|string[] $category Category ID, name, slug, or array of such
* to check against.
* @param int|WP_Post $post Optional. Post to check. Defaults to the current post.
* @return bool True if the current post is in any of the given categories.
*/
function in_category( $category, $post = null ) {
if ( empty( $category ) ) {
return false;
}
return has_category( $category, $post );
}
/**
* Displays category list for a post in either HTML list or custom format.
*
* @since 0.71
*
* @param string $separator Optional. Separator between the categories. By default, the links are placed
* in an unordered list. An empty string will result in the default behavior.
* @param string $parents Optional. How to display the parents. Accepts 'multiple', 'single', or empty.
* Default empty string.
* @param int $post_id Optional. ID of the post to retrieve categories for. Defaults to the current post.
*/
function the_category( $separator = '', $parents = '', $post_id = false ) {
echo get_the_category_list( $separator, $parents, $post_id );
}
/**
* Retrieves category description.
*
* @since 1.0.0
*
* @param int $category Optional. Category ID. Defaults to the current category ID.
* @return string Category description, if available.
*/
function category_description( $category = 0 ) {
return term_description( $category );
}
/**
* Displays or retrieves the HTML dropdown list of categories.
*
* The 'hierarchical' argument, which is disabled by default, will override the
* depth argument, unless it is true. When the argument is false, it will
* display all of the categories. When it is enabled it will use the value in
* the 'depth' argument.
*
* @since 2.1.0
* @since 4.2.0 Introduced the `value_field` argument.
* @since 4.6.0 Introduced the `required` argument.
* @since 6.1.0 Introduced the `aria_describedby` argument.
*
* @param array|string $args {
* Optional. Array or string of arguments to generate a categories drop-down element. See WP_Term_Query::__construct()
* for information on additional accepted arguments.
*
* @type string $show_option_all Text to display for showing all categories. Default empty.
* @type string $show_option_none Text to display for showing no categories. Default empty.
* @type string $option_none_value Value to use when no category is selected. Default empty.
* @type string $orderby Which column to use for ordering categories. See get_terms() for a list
* of accepted values. Default 'id' (term_id).
* @type bool $pad_counts See get_terms() for an argument description. Default false.
* @type bool|int $show_count Whether to include post counts. Accepts 0, 1, or their bool equivalents.
* Default 0.
* @type bool|int $echo Whether to echo or return the generated markup. Accepts 0, 1, or their
* bool equivalents. Default 1.
* @type bool|int $hierarchical Whether to traverse the taxonomy hierarchy. Accepts 0, 1, or their bool
* equivalents. Default 0.
* @type int $depth Maximum depth. Default 0.
* @type int $tab_index Tab index for the select element. Default 0 (no tabindex).
* @type string $name Value for the 'name' attribute of the select element. Default 'cat'.
* @type string $id Value for the 'id' attribute of the select element. Defaults to the value
* of `$name`.
* @type string $class Value for the 'class' attribute of the select element. Default 'postform'.
* @type int|string $selected Value of the option that should be selected. Default 0.
* @type string $value_field Term field that should be used to populate the 'value' attribute
* of the option elements. Accepts any valid term field: 'term_id', 'name',
* 'slug', 'term_group', 'term_taxonomy_id', 'taxonomy', 'description',
* 'parent', 'count'. Default 'term_id'.
* @type string|array $taxonomy Name of the taxonomy or taxonomies to retrieve. Default 'category'.
* @type bool $hide_if_empty True to skip generating markup if no categories are found.
* Default false (create select element even if no categories are found).
* @type bool $required Whether the `<select>` element should have the HTML5 'required' attribute.
* Default false.
* @type Walker $walker Walker object to use to build the output. Default empty which results in a
* Walker_CategoryDropdown instance being used.
* @type string $aria_describedby The 'id' of an element that contains descriptive text for the select.
* Default empty string.
* }
* @return string HTML dropdown list of categories.
*/
function wp_dropdown_categories( $args = '' ) {
$defaults = array(
'show_option_all' => '',
'show_option_none' => '',
'orderby' => 'id',
'order' => 'ASC',
'show_count' => 0,
'hide_empty' => 1,
'child_of' => 0,
'exclude' => '',
'echo' => 1,
'selected' => 0,
'hierarchical' => 0,
'name' => 'cat',
'id' => '',
'class' => 'postform',
'depth' => 0,
'tab_index' => 0,
'taxonomy' => 'category',
'hide_if_empty' => false,
'option_none_value' => -1,
'value_field' => 'term_id',
'required' => false,
'aria_describedby' => '',
);
$defaults['selected'] = ( is_category() ) ? get_query_var( 'cat' ) : 0;
// Back compat.
if ( isset( $args['type'] ) && 'link' === $args['type'] ) {
_deprecated_argument(
__FUNCTION__,
'3.0.0',
sprintf(
/* translators: 1: "type => link", 2: "taxonomy => link_category" */
__( '%1$s is deprecated. Use %2$s instead.' ),
'<code>type => link</code>',
'<code>taxonomy => link_category</code>'
)
);
$args['taxonomy'] = 'link_category';
}
// Parse incoming $args into an array and merge it with $defaults.
$parsed_args = wp_parse_args( $args, $defaults );
$option_none_value = $parsed_args['option_none_value'];
if ( ! isset( $parsed_args['pad_counts'] ) && $parsed_args['show_count'] && $parsed_args['hierarchical'] ) {
$parsed_args['pad_counts'] = true;
}
$tab_index = $parsed_args['tab_index'];
$tab_index_attribute = '';
if ( (int) $tab_index > 0 ) {
$tab_index_attribute = " tabindex=\"$tab_index\"";
}
// Avoid clashes with the 'name' param of get_terms().
$get_terms_args = $parsed_args;
unset( $get_terms_args['name'] );
$categories = get_terms( $get_terms_args );
$name = esc_attr( $parsed_args['name'] );
$class = esc_attr( $parsed_args['class'] );
$id = $parsed_args['id'] ? esc_attr( $parsed_args['id'] ) : $name;
$required = $parsed_args['required'] ? 'required' : '';
$aria_describedby_attribute = $parsed_args['aria_describedby'] ? ' aria-describedby="' . esc_attr( $parsed_args['aria_describedby'] ) . '"' : '';
if ( ! $parsed_args['hide_if_empty'] || ! empty( $categories ) ) {
$output = "<select $required name='$name' id='$id' class='$class'$tab_index_attribute$aria_describedby_attribute>\n";
} else {
$output = '';
}
if ( empty( $categories ) && ! $parsed_args['hide_if_empty'] && ! empty( $parsed_args['show_option_none'] ) ) {
/**
* Filters a taxonomy drop-down display element.
*
* A variety of taxonomy drop-down display elements can be modified
* just prior to display via this filter. Filterable arguments include
* 'show_option_none', 'show_option_all', and various forms of the
* term name.
*
* @since 1.2.0
*
* @see wp_dropdown_categories()
*
* @param string $element Category name.
* @param WP_Term|null $category The category object, or null if there's no corresponding category.
*/
$show_option_none = apply_filters( 'list_cats', $parsed_args['show_option_none'], null );
$output .= "\t<option value='" . esc_attr( $option_none_value ) . "' selected='selected'>$show_option_none</option>\n";
}
if ( ! empty( $categories ) ) {
if ( $parsed_args['show_option_all'] ) {
/** This filter is documented in wp-includes/category-template.php */
$show_option_all = apply_filters( 'list_cats', $parsed_args['show_option_all'], null );
$selected = ( '0' === (string) $parsed_args['selected'] ) ? " selected='selected'" : '';
$output .= "\t<option value='0'$selected>$show_option_all</option>\n";
}
if ( $parsed_args['show_option_none'] ) {
/** This filter is documented in wp-includes/category-template.php */
$show_option_none = apply_filters( 'list_cats', $parsed_args['show_option_none'], null );
$selected = selected( $option_none_value, $parsed_args['selected'], false );
$output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$selected>$show_option_none</option>\n";
}
if ( $parsed_args['hierarchical'] ) {
$depth = $parsed_args['depth']; // Walk the full depth.
} else {
$depth = -1; // Flat.
}
$output .= walk_category_dropdown_tree( $categories, $depth, $parsed_args );
}
if ( ! $parsed_args['hide_if_empty'] || ! empty( $categories ) ) {
$output .= "</select>\n";
}
/**
* Filters the taxonomy drop-down output.
*
* @since 2.1.0
*
* @param string $output HTML output.
* @param array $parsed_args Arguments used to build the drop-down.
*/
$output = apply_filters( 'wp_dropdown_cats', $output, $parsed_args );
if ( $parsed_args['echo'] ) {
echo $output;
}
return $output;
}
/**
* Displays or retrieves the HTML list of categories.
*
* @since 2.1.0
* @since 4.4.0 Introduced the `hide_title_if_empty` and `separator` arguments.
* @since 4.4.0 The `current_category` argument was modified to optionally accept an array of values.
* @since 6.1.0 Default value of the 'use_desc_for_title' argument was changed from 1 to 0.
*
* @param array|string $args {
* Array of optional arguments. See get_categories(), get_terms(), and WP_Term_Query::__construct()
* for information on additional accepted arguments.
*
* @type int|int[] $current_category ID of category, or array of IDs of categories, that should get the
* 'current-cat' class. Default 0.
* @type int $depth Category depth. Used for tab indentation. Default 0.
* @type bool|int $echo Whether to echo or return the generated markup. Accepts 0, 1, or their
* bool equivalents. Default 1.
* @type int[]|string $exclude Array or comma/space-separated string of term IDs to exclude.
* If `$hierarchical` is true, descendants of `$exclude` terms will also
* be excluded; see `$exclude_tree`. See get_terms().
* Default empty string.
* @type int[]|string $exclude_tree Array or comma/space-separated string of term IDs to exclude, along
* with their descendants. See get_terms(). Default empty string.
* @type string $feed Text to use for the feed link. Default 'Feed for all posts filed
* under [cat name]'.
* @type string $feed_image URL of an image to use for the feed link. Default empty string.
* @type string $feed_type Feed type. Used to build feed link. See get_term_feed_link().
* Default empty string (default feed).
* @type bool $hide_title_if_empty Whether to hide the `$title_li` element if there are no terms in
* the list. Default false (title will always be shown).
* @type string $separator Separator between links. Default '<br />'.
* @type bool|int $show_count Whether to include post counts. Accepts 0, 1, or their bool equivalents.
* Default 0.
* @type string $show_option_all Text to display for showing all categories. Default empty string.
* @type string $show_option_none Text to display for the 'no categories' option.
* Default 'No categories'.
* @type string $style The style used to display the categories list. If 'list', categories
* will be output as an unordered list. If left empty or another value,
* categories will be output separated by `<br>` tags. Default 'list'.
* @type string $taxonomy Name of the taxonomy to retrieve. Default 'category'.
* @type string $title_li Text to use for the list title `<li>` element. Pass an empty string
* to disable. Default 'Categories'.
* @type bool|int $use_desc_for_title Whether to use the category description as the title attribute.
* Accepts 0, 1, or their bool equivalents. Default 0.
* @type Walker $walker Walker object to use to build the output. Default empty which results
* in a Walker_Category instance being used.
* }
* @return void|string|false Void if 'echo' argument is true, HTML list of categories if 'echo' is false.
* False if the taxonomy does not exist.
*/
function wp_list_categories( $args = '' ) {
$defaults = array(
'child_of' => 0,
'current_category' => 0,
'depth' => 0,
'echo' => 1,
'exclude' => '',
'exclude_tree' => '',
'feed' => '',
'feed_image' => '',
'feed_type' => '',
'hide_empty' => 1,
'hide_title_if_empty' => false,
'hierarchical' => true,
'order' => 'ASC',
'orderby' => 'name',
'separator' => '<br />',
'show_count' => 0,
'show_option_all' => '',
'show_option_none' => __( 'No categories' ),
'style' => 'list',
'taxonomy' => 'category',
'title_li' => __( 'Categories' ),
'use_desc_for_title' => 0,
);
$parsed_args = wp_parse_args( $args, $defaults );
if ( ! isset( $parsed_args['pad_counts'] ) && $parsed_args['show_count'] && $parsed_args['hierarchical'] ) {
$parsed_args['pad_counts'] = true;
}
// Descendants of exclusions should be excluded too.
if ( $parsed_args['hierarchical'] ) {
$exclude_tree = array();
if ( $parsed_args['exclude_tree'] ) {
$exclude_tree = array_merge( $exclude_tree, wp_parse_id_list( $parsed_args['exclude_tree'] ) );
}
if ( $parsed_args['exclude'] ) {
$exclude_tree = array_merge( $exclude_tree, wp_parse_id_list( $parsed_args['exclude'] ) );
}
$parsed_args['exclude_tree'] = $exclude_tree;
$parsed_args['exclude'] = '';
}
if ( ! isset( $parsed_args['class'] ) ) {
$parsed_args['class'] = ( 'category' === $parsed_args['taxonomy'] ) ? 'categories' : $parsed_args['taxonomy'];
}
if ( ! taxonomy_exists( $parsed_args['taxonomy'] ) ) {
return false;
}
$show_option_all = $parsed_args['show_option_all'];
$show_option_none = $parsed_args['show_option_none'];
$categories = get_categories( $parsed_args );
$output = '';
if ( $parsed_args['title_li'] && 'list' === $parsed_args['style']
&& ( ! empty( $categories ) || ! $parsed_args['hide_title_if_empty'] )
) {
$output = '<li class="' . esc_attr( $parsed_args['class'] ) . '">' . $parsed_args['title_li'] . '<ul>';
}
if ( empty( $categories ) ) {
if ( ! empty( $show_option_none ) ) {
if ( 'list' === $parsed_args['style'] ) {
$output .= '<li class="cat-item-none">' . $show_option_none . '</li>';
} else {
$output .= $show_option_none;
}
}
} else {
if ( ! empty( $show_option_all ) ) {
$posts_page = '';
// For taxonomies that belong only to custom post types, point to a valid archive.
$taxonomy_object = get_taxonomy( $parsed_args['taxonomy'] );
if ( ! in_array( 'post', $taxonomy_object->object_type, true ) && ! in_array( 'page', $taxonomy_object->object_type, true ) ) {
foreach ( $taxonomy_object->object_type as $object_type ) {
$_object_type = get_post_type_object( $object_type );
// Grab the first one.
if ( ! empty( $_object_type->has_archive ) ) {
$posts_page = get_post_type_archive_link( $object_type );
break;
}
}
}
// Fallback for the 'All' link is the posts page.
if ( ! $posts_page ) {
if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) ) {
$posts_page = get_permalink( get_option( 'page_for_posts' ) );
} else {
$posts_page = home_url( '/' );
}
}
$posts_page = esc_url( $posts_page );
if ( 'list' === $parsed_args['style'] ) {
$output .= "<li class='cat-item-all'><a href='$posts_page'>$show_option_all</a></li>";
} else {
$output .= "<a href='$posts_page'>$show_option_all</a>";
}
}
if ( empty( $parsed_args['current_category'] ) && ( is_category() || is_tax() || is_tag() ) ) {
$current_term_object = get_queried_object();
if ( $current_term_object && $parsed_args['taxonomy'] === $current_term_object->taxonomy ) {
$parsed_args['current_category'] = get_queried_object_id();
}
}
if ( $parsed_args['hierarchical'] ) {
$depth = $parsed_args['depth'];
} else {
$depth = -1; // Flat.
}
$output .= walk_category_tree( $categories, $depth, $parsed_args );
}
if ( $parsed_args['title_li'] && 'list' === $parsed_args['style']
&& ( ! empty( $categories ) || ! $parsed_args['hide_title_if_empty'] )
) {
$output .= '</ul></li>';
}
/**
* Filters the HTML output of a taxonomy list.
*
* @since 2.1.0
*
* @param string $output HTML output.
* @param array|string $args An array or query string of taxonomy-listing arguments. See
* wp_list_categories() for information on accepted arguments.
*/
$html = apply_filters( 'wp_list_categories', $output, $args );
if ( $parsed_args['echo'] ) {
echo $html;
} else {
return $html;
}
}
/**
* Displays a tag cloud.
*
* Outputs a list of tags in what is called a 'tag cloud', where the size of each tag
* is determined by how many times that particular tag has been assigned to posts.
*
* @since 2.3.0
* @since 2.8.0 Added the `taxonomy` argument.
* @since 4.8.0 Added the `show_count` argument.
*
* @param array|string $args {
* Optional. Array or string of arguments for displaying a tag cloud. See wp_generate_tag_cloud()
* and get_terms() for the full lists of arguments that can be passed in `$args`.
*
* @type int $number The number of tags to display. Accepts any positive integer
* or zero to return all. Default 45.
* @type string $link Whether to display term editing links or term permalinks.
* Accepts 'edit' and 'view'. Default 'view'.
* @type string $post_type The post type. Used to highlight the proper post type menu
* on the linked edit page. Defaults to the first post type
* associated with the taxonomy.
* @type bool $echo Whether or not to echo the return value. Default true.
* }
* @return void|string|string[] Void if 'echo' argument is true, or on failure. Otherwise, tag cloud
* as a string or an array, depending on 'format' argument.
*/
function wp_tag_cloud( $args = '' ) {
$defaults = array(
'smallest' => 8,
'largest' => 22,
'unit' => 'pt',
'number' => 45,
'format' => 'flat',
'separator' => "\n",
'orderby' => 'name',
'order' => 'ASC',
'exclude' => '',
'include' => '',
'link' => 'view',
'taxonomy' => 'post_tag',
'post_type' => '',
'echo' => true,
'show_count' => 0,
);
$args = wp_parse_args( $args, $defaults );
$tags = get_terms(
array_merge(
$args,
array(
'orderby' => 'count',
'order' => 'DESC',
)
)
); // Always query top tags.
if ( empty( $tags ) || is_wp_error( $tags ) ) {
return;
}
foreach ( $tags as $key => $tag ) {
if ( 'edit' === $args['link'] ) {
$link = get_edit_term_link( $tag, $tag->taxonomy, $args['post_type'] );
} else {
$link = get_term_link( $tag, $tag->taxonomy );
}
if ( is_wp_error( $link ) ) {
return;
}
$tags[ $key ]->link = $link;
$tags[ $key ]->id = $tag->term_id;
}
// Here's where those top tags get sorted according to $args.
$return = wp_generate_tag_cloud( $tags, $args );
/**
* Filters the tag cloud output.
*
* @since 2.3.0
*
* @param string|string[] $return Tag cloud as a string or an array, depending on 'format' argument.
* @param array $args An array of tag cloud arguments. See wp_tag_cloud()
* for information on accepted arguments.
*/
$return = apply_filters( 'wp_tag_cloud', $return, $args );
if ( 'array' === $args['format'] || empty( $args['echo'] ) ) {
return $return;
}
echo $return;
}
/**
* Default topic count scaling for tag links.
*
* @since 2.9.0
*
* @param int $count Number of posts with that tag.
* @return int Scaled count.
*/
function default_topic_count_scale( $count ) {
return round( log10( $count + 1 ) * 100 );
}
/**
* Generates a tag cloud (heatmap) from provided data.
*
* @todo Complete functionality.
* @since 2.3.0
* @since 4.8.0 Added the `show_count` argument.
*
* @param WP_Term[] $tags Array of WP_Term objects to generate the tag cloud for.
* @param string|array $args {
* Optional. Array or string of arguments for generating a tag cloud.
*
* @type int $smallest Smallest font size used to display tags. Paired
* with the value of `$unit`, to determine CSS text
* size unit. Default 8 (pt).
* @type int $largest Largest font size used to display tags. Paired
* with the value of `$unit`, to determine CSS text
* size unit. Default 22 (pt).
* @type string $unit CSS text size unit to use with the `$smallest`
* and `$largest` values. Accepts any valid CSS text
* size unit. Default 'pt'.
* @type int $number The number of tags to return. Accepts any
* positive integer or zero to return all.
* Default 0.
* @type string $format Format to display the tag cloud in. Accepts 'flat'
* (tags separated with spaces), 'list' (tags displayed
* in an unordered list), or 'array' (returns an array).
* Default 'flat'.
* @type string $separator HTML or text to separate the tags. Default "\n" (newline).
* @type string $orderby Value to order tags by. Accepts 'name' or 'count'.
* Default 'name'. The {@see 'tag_cloud_sort'} filter
* can also affect how tags are sorted.
* @type string $order How to order the tags. Accepts 'ASC' (ascending),
* 'DESC' (descending), or 'RAND' (random). Default 'ASC'.
* @type int|bool $filter Whether to enable filtering of the final output
* via {@see 'wp_generate_tag_cloud'}. Default 1.
* @type array $topic_count_text Nooped plural text from _n_noop() to supply to
* tag counts. Default null.
* @type callable $topic_count_text_callback Callback used to generate nooped plural text for
* tag counts based on the count. Default null.
* @type callable $topic_count_scale_callback Callback used to determine the tag count scaling
* value. Default default_topic_count_scale().
* @type bool|int $show_count Whether to display the tag counts. Default 0. Accepts
* 0, 1, or their bool equivalents.
* }
* @return string|string[] Tag cloud as a string or an array, depending on 'format' argument.
*/
function wp_generate_tag_cloud( $tags, $args = '' ) {
$defaults = array(
'smallest' => 8,
'largest' => 22,
'unit' => 'pt',
'number' => 0,
'format' => 'flat',
'separator' => "\n",
'orderby' => 'name',
'order' => 'ASC',
'topic_count_text' => null,
'topic_count_text_callback' => null,
'topic_count_scale_callback' => 'default_topic_count_scale',
'filter' => 1,
'show_count' => 0,
);
$args = wp_parse_args( $args, $defaults );
$return = ( 'array' === $args['format'] ) ? array() : '';
if ( empty( $tags ) ) {
return $return;
}
// Juggle topic counts.
if ( isset( $args['topic_count_text'] ) ) {
// First look for nooped plural support via topic_count_text.
$translate_nooped_plural = $args['topic_count_text'];
} elseif ( ! empty( $args['topic_count_text_callback'] ) ) {
// Look for the alternative callback style. Ignore the previous default.
if ( 'default_topic_count_text' === $args['topic_count_text_callback'] ) {
/* translators: %s: Number of items (tags). */
$translate_nooped_plural = _n_noop( '%s item', '%s items' );
} else {
$translate_nooped_plural = false;
}
} elseif ( isset( $args['single_text'] ) && isset( $args['multiple_text'] ) ) {
// If no callback exists, look for the old-style single_text and multiple_text arguments.
// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralSingular,WordPress.WP.I18n.NonSingularStringLiteralPlural
$translate_nooped_plural = _n_noop( $args['single_text'], $args['multiple_text'] );
} else {
// This is the default for when no callback, plural, or argument is passed in.
/* translators: %s: Number of items (tags). */
$translate_nooped_plural = _n_noop( '%s item', '%s items' );
}
/**
* Filters how the items in a tag cloud are sorted.
*
* @since 2.8.0
*
* @param WP_Term[] $tags Ordered array of terms.
* @param array $args An array of tag cloud arguments.
*/
$tags_sorted = apply_filters( 'tag_cloud_sort', $tags, $args );
if ( empty( $tags_sorted ) ) {
return $return;
}
if ( $tags_sorted !== $tags ) {
$tags = $tags_sorted;
unset( $tags_sorted );
} else {
if ( 'RAND' === $args['order'] ) {
shuffle( $tags );
} else {
// SQL cannot save you; this is a second (potentially different) sort on a subset of data.
if ( 'name' === $args['orderby'] ) {
uasort( $tags, '_wp_object_name_sort_cb' );
} else {
uasort( $tags, '_wp_object_count_sort_cb' );
}
if ( 'DESC' === $args['order'] ) {
$tags = array_reverse( $tags, true );
}
}
}
if ( $args['number'] > 0 ) {
$tags = array_slice( $tags, 0, $args['number'] );
}
$counts = array();
$real_counts = array(); // For the alt tag.
foreach ( (array) $tags as $key => $tag ) {
$real_counts[ $key ] = $tag->count;
$counts[ $key ] = call_user_func( $args['topic_count_scale_callback'], $tag->count );
}
$min_count = min( $counts );
$spread = max( $counts ) - $min_count;
if ( $spread <= 0 ) {
$spread = 1;
}
$font_spread = $args['largest'] - $args['smallest'];
if ( $font_spread < 0 ) {
$font_spread = 1;
}
$font_step = $font_spread / $spread;
$aria_label = false;
/*
* Determine whether to output an 'aria-label' attribute with the tag name and count.
* When tags have a different font size, they visually convey an important information
* that should be available to assistive technologies too. On the other hand, sometimes
* themes set up the Tag Cloud to display all tags with the same font size (setting
* the 'smallest' and 'largest' arguments to the same value).
* In order to always serve the same content to all users, the 'aria-label' gets printed out:
* - when tags have a different size
* - when the tag count is displayed (for example when users check the checkbox in the
* Tag Cloud widget), regardless of the tags font size
*/
if ( $args['show_count'] || 0 !== $font_spread ) {
$aria_label = true;
}
// Assemble the data that will be used to generate the tag cloud markup.
$tags_data = array();
foreach ( $tags as $key => $tag ) {
$tag_id = isset( $tag->id ) ? $tag->id : $key;
$count = $counts[ $key ];
$real_count = $real_counts[ $key ];
if ( $translate_nooped_plural ) {
$formatted_count = sprintf( translate_nooped_plural( $translate_nooped_plural, $real_count ), number_format_i18n( $real_count ) );
} else {
$formatted_count = call_user_func( $args['topic_count_text_callback'], $real_count, $tag, $args );
}
$tags_data[] = array(
'id' => $tag_id,
'url' => ( '#' !== $tag->link ) ? $tag->link : '#',
'role' => ( '#' !== $tag->link ) ? '' : ' role="button"',
'name' => $tag->name,
'formatted_count' => $formatted_count,
'slug' => $tag->slug,
'real_count' => $real_count,
'class' => 'tag-cloud-link tag-link-' . $tag_id,
'font_size' => $args['smallest'] + ( $count - $min_count ) * $font_step,
'aria_label' => $aria_label ? sprintf( ' aria-label="%1$s (%2$s)"', esc_attr( $tag->name ), esc_attr( $formatted_count ) ) : '',
'show_count' => $args['show_count'] ? '<span class="tag-link-count"> (' . $real_count . ')</span>' : '',
);
}
/**
* Filters the data used to generate the tag cloud.
*
* @since 4.3.0
*
* @param array[] $tags_data An array of term data arrays for terms used to generate the tag cloud.
*/
$tags_data = apply_filters( 'wp_generate_tag_cloud_data', $tags_data );
$a = array();
// Generate the output links array.
foreach ( $tags_data as $key => $tag_data ) {
$class = $tag_data['class'] . ' tag-link-position-' . ( $key + 1 );
$a[] = sprintf(
'<a href="%1$s"%2$s class="%3$s" style="font-size: %4$s;"%5$s>%6$s%7$s</a>',
esc_url( $tag_data['url'] ),
$tag_data['role'],
esc_attr( $class ),
esc_attr( str_replace( ',', '.', $tag_data['font_size'] ) . $args['unit'] ),
$tag_data['aria_label'],
esc_html( $tag_data['name'] ),
$tag_data['show_count']
);
}
switch ( $args['format'] ) {
case 'array':
$return =& $a;
break;
case 'list':
/*
* Force role="list", as some browsers (sic: Safari 10) don't expose to assistive
* technologies the default role when the list is styled with `list-style: none`.
* Note: this is redundant but doesn't harm.
*/
$return = "<ul class='wp-tag-cloud' role='list'>\n\t<li>";
$return .= implode( "</li>\n\t<li>", $a );
$return .= "</li>\n</ul>\n";
break;
default:
$return = implode( $args['separator'], $a );
break;
}
if ( $args['filter'] ) {
/**
* Filters the generated output of a tag cloud.
*
* The filter is only evaluated if a true value is passed
* to the $filter argument in wp_generate_tag_cloud().
*
* @since 2.3.0
*
* @see wp_generate_tag_cloud()
*
* @param string[]|string $return String containing the generated HTML tag cloud output
* or an array of tag links if the 'format' argument
* equals 'array'.
* @param WP_Term[] $tags An array of terms used in the tag cloud.
* @param array $args An array of wp_generate_tag_cloud() arguments.
*/
return apply_filters( 'wp_generate_tag_cloud', $return, $tags, $args );
} else {
return $return;
}
}
/**
* Serves as a callback for comparing objects based on name.
*
* Used with `uasort()`.
*
* @since 3.1.0
* @access private
*
* @param object $a The first object to compare.
* @param object $b The second object to compare.
* @return int Negative number if `$a->name` is less than `$b->name`, zero if they are equal,
* or greater than zero if `$a->name` is greater than `$b->name`.
*/
function _wp_object_name_sort_cb( $a, $b ) {
return strnatcasecmp( $a->name, $b->name );
}
/**
* Serves as a callback for comparing objects based on count.
*
* Used with `uasort()`.
*
* @since 3.1.0
* @access private
*
* @param object $a The first object to compare.
* @param object $b The second object to compare.
* @return int Negative number if `$a->count` is less than `$b->count`, zero if they are equal,
* or greater than zero if `$a->count` is greater than `$b->count`.
*/
function _wp_object_count_sort_cb( $a, $b ) {
return ( $a->count - $b->count );
}
//
// Helper functions.
//
/**
* Retrieves HTML list content for category list.
*
* @since 2.1.0
* @since 5.3.0 Formalized the existing `...$args` parameter by adding it
* to the function signature.
*
* @uses Walker_Category to create HTML list content.
* @see Walker::walk() for parameters and return description.
*
* @param mixed ...$args Elements array, maximum hierarchical depth and optional additional arguments.
* @return string
*/
function walk_category_tree( ...$args ) {
// The user's options are the third parameter.
if ( empty( $args[2]['walker'] ) || ! ( $args[2]['walker'] instanceof Walker ) ) {
$walker = new Walker_Category();
} else {
/**
* @var Walker $walker
*/
$walker = $args[2]['walker'];
}
return $walker->walk( ...$args );
}
/**
* Retrieves HTML dropdown (select) content for category list.
*
* @since 2.1.0
* @since 5.3.0 Formalized the existing `...$args` parameter by adding it
* to the function signature.
*
* @uses Walker_CategoryDropdown to create HTML dropdown content.
* @see Walker::walk() for parameters and return description.
*
* @param mixed ...$args Elements array, maximum hierarchical depth and optional additional arguments.
* @return string
*/
function walk_category_dropdown_tree( ...$args ) {
// The user's options are the third parameter.
if ( empty( $args[2]['walker'] ) || ! ( $args[2]['walker'] instanceof Walker ) ) {
$walker = new Walker_CategoryDropdown();
} else {
/**
* @var Walker $walker
*/
$walker = $args[2]['walker'];
}
return $walker->walk( ...$args );
}
//
// Tags.
//
/**
* Retrieves the link to the tag.
*
* @since 2.3.0
*
* @see get_term_link()
*
* @param int|object $tag Tag ID or object.
* @return string Link on success, empty string if tag does not exist.
*/
function get_tag_link( $tag ) {
return get_category_link( $tag );
}
/**
* Retrieves the tags for a post.
*
* @since 2.3.0
*
* @param int|WP_Post $post Post ID or object.
* @return WP_Term[]|false|WP_Error Array of WP_Term objects on success, false if there are no terms
* or the post does not exist, WP_Error on failure.
*/
function get_the_tags( $post = 0 ) {
$terms = get_the_terms( $post, 'post_tag' );
/**
* Filters the array of tags for the given post.
*
* @since 2.3.0
*
* @see get_the_terms()
*
* @param WP_Term[]|false|WP_Error $terms Array of WP_Term objects on success, false if there are no terms
* or the post does not exist, WP_Error on failure.
*/
return apply_filters( 'get_the_tags', $terms );
}
/**
* Retrieves the tags for a post formatted as a string.
*
* @since 2.3.0
*
* @param string $before Optional. String to use before the tags. Default empty.
* @param string $sep Optional. String to use between the tags. Default empty.
* @param string $after Optional. String to use after the tags. Default empty.
* @param int $post_id Optional. Post ID. Defaults to the current post ID.
* @return string|false|WP_Error A list of tags on success, false if there are no terms,
* WP_Error on failure.
*/
function get_the_tag_list( $before = '', $sep = '', $after = '', $post_id = 0 ) {
$tag_list = get_the_term_list( $post_id, 'post_tag', $before, $sep, $after );
/**
* Filters the tags list for a given post.
*
* @since 2.3.0
*
* @param string $tag_list List of tags.
* @param string $before String to use before the tags.
* @param string $sep String to use between the tags.
* @param string $after String to use after the tags.
* @param int $post_id Post ID.
*/
return apply_filters( 'the_tags', $tag_list, $before, $sep, $after, $post_id );
}
/**
* Displays the tags for a post.
*
* @since 2.3.0
*
* @param string $before Optional. String to use before the tags. Defaults to 'Tags:'.
* @param string $sep Optional. String to use between the tags. Default ', '.
* @param string $after Optional. String to use after the tags. Default empty.
*/
function the_tags( $before = null, $sep = ', ', $after = '' ) {
if ( null === $before ) {
$before = __( 'Tags: ' );
}
$the_tags = get_the_tag_list( $before, $sep, $after );
if ( ! is_wp_error( $the_tags ) ) {
echo $the_tags;
}
}
/**
* Retrieves tag description.
*
* @since 2.8.0
*
* @param int $tag Optional. Tag ID. Defaults to the current tag ID.
* @return string Tag description, if available.
*/
function tag_description( $tag = 0 ) {
return term_description( $tag );
}
/**
* Retrieves term description.
*
* @since 2.8.0
* @since 4.9.2 The `$taxonomy` parameter was deprecated.
*
* @param int $term Optional. Term ID. Defaults to the current term ID.
* @param null $deprecated Deprecated. Not used.
* @return string Term description, if available.
*/
function term_description( $term = 0, $deprecated = null ) {
if ( ! $term && ( is_tax() || is_tag() || is_category() ) ) {
$term = get_queried_object();
if ( $term ) {
$term = $term->term_id;
}
}
$description = get_term_field( 'description', $term );
return is_wp_error( $description ) ? '' : $description;
}
/**
* Retrieves the terms of the taxonomy that are attached to the post.
*
* @since 2.5.0
*
* @param int|WP_Post $post Post ID or object.
* @param string $taxonomy Taxonomy name.
* @return WP_Term[]|false|WP_Error Array of WP_Term objects on success, false if there are no terms
* or the post does not exist, WP_Error on failure.
*/
function get_the_terms( $post, $taxonomy ) {
$post = get_post( $post );
if ( ! $post ) {
return false;
}
$terms = get_object_term_cache( $post->ID, $taxonomy );
if ( false === $terms ) {
$terms = wp_get_object_terms( $post->ID, $taxonomy );
if ( ! is_wp_error( $terms ) ) {
$term_ids = wp_list_pluck( $terms, 'term_id' );
wp_cache_add( $post->ID, $term_ids, $taxonomy . '_relationships' );
}
}
/**
* Filters the list of terms attached to the given post.
*
* @since 3.1.0
*
* @param WP_Term[]|WP_Error $terms Array of attached terms, or WP_Error on failure.
* @param int $post_id Post ID.
* @param string $taxonomy Name of the taxonomy.
*/
$terms = apply_filters( 'get_the_terms', $terms, $post->ID, $taxonomy );
if ( empty( $terms ) ) {
return false;
}
return $terms;
}
/**
* Retrieves a post's terms as a list with specified format.
*
* Terms are linked to their respective term listing pages.
*
* @since 2.5.0
*
* @param int $post_id Post ID.
* @param string $taxonomy Taxonomy name.
* @param string $before Optional. String to use before the terms. Default empty.
* @param string $sep Optional. String to use between the terms. Default empty.
* @param string $after Optional. String to use after the terms. Default empty.
* @return string|false|WP_Error A list of terms on success, false if there are no terms,
* WP_Error on failure.
*/
function get_the_term_list( $post_id, $taxonomy, $before = '', $sep = '', $after = '' ) {
$terms = get_the_terms( $post_id, $taxonomy );
if ( is_wp_error( $terms ) ) {
return $terms;
}
if ( empty( $terms ) ) {
return false;
}
$links = array();
foreach ( $terms as $term ) {
$link = get_term_link( $term, $taxonomy );
if ( is_wp_error( $link ) ) {
return $link;
}
$links[] = '<a href="' . esc_url( $link ) . '" rel="tag">' . $term->name . '</a>';
}
/**
* Filters the term links for a given taxonomy.
*
* The dynamic portion of the hook name, `$taxonomy`, refers
* to the taxonomy slug.
*
* Possible hook names include:
*
* - `term_links-category`
* - `term_links-post_tag`
* - `term_links-post_format`
*
* @since 2.5.0
*
* @param string[] $links An array of term links.
*/
$term_links = apply_filters( "term_links-{$taxonomy}", $links ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
return $before . implode( $sep, $term_links ) . $after;
}
/**
* Retrieves term parents with separator.
*
* @since 4.8.0
*
* @param int $term_id Term ID.
* @param string $taxonomy Taxonomy name.
* @param string|array $args {
* Array of optional arguments.
*
* @type string $format Use term names or slugs for display. Accepts 'name' or 'slug'.
* Default 'name'.
* @type string $separator Separator for between the terms. Default '/'.
* @type bool $link Whether to format as a link. Default true.
* @type bool $inclusive Include the term to get the parents for. Default true.
* }
* @return string|WP_Error A list of term parents on success, WP_Error or empty string on failure.
*/
function get_term_parents_list( $term_id, $taxonomy, $args = array() ) {
$list = '';
$term = get_term( $term_id, $taxonomy );
if ( is_wp_error( $term ) ) {
return $term;
}
if ( ! $term ) {
return $list;
}
$term_id = $term->term_id;
$defaults = array(
'format' => 'name',
'separator' => '/',
'link' => true,
'inclusive' => true,
);
$args = wp_parse_args( $args, $defaults );
foreach ( array( 'link', 'inclusive' ) as $bool ) {
$args[ $bool ] = wp_validate_boolean( $args[ $bool ] );
}
$parents = get_ancestors( $term_id, $taxonomy, 'taxonomy' );
if ( $args['inclusive'] ) {
array_unshift( $parents, $term_id );
}
foreach ( array_reverse( $parents ) as $term_id ) {
$parent = get_term( $term_id, $taxonomy );
$name = ( 'slug' === $args['format'] ) ? $parent->slug : $parent->name;
if ( $args['link'] ) {
$list .= '<a href="' . esc_url( get_term_link( $parent->term_id, $taxonomy ) ) . '">' . $name . '</a>' . $args['separator'];
} else {
$list .= $name . $args['separator'];
}
}
return $list;
}
/**
* Displays the terms for a post in a list.
*
* @since 2.5.0
*
* @param int $post_id Post ID.
* @param string $taxonomy Taxonomy name.
* @param string $before Optional. String to use before the terms. Default empty.
* @param string $sep Optional. String to use between the terms. Default ', '.
* @param string $after Optional. String to use after the terms. Default empty.
* @return void|false Void on success, false on failure.
*/
function the_terms( $post_id, $taxonomy, $before = '', $sep = ', ', $after = '' ) {
$term_list = get_the_term_list( $post_id, $taxonomy, $before, $sep, $after );
if ( is_wp_error( $term_list ) ) {
return false;
}
/**
* Filters the list of terms to display.
*
* @since 2.9.0
*
* @param string $term_list List of terms to display.
* @param string $taxonomy The taxonomy name.
* @param string $before String to use before the terms.
* @param string $sep String to use between the terms.
* @param string $after String to use after the terms.
*/
echo apply_filters( 'the_terms', $term_list, $taxonomy, $before, $sep, $after );
}
/**
* Checks if the current post has any of given category.
*
* The given categories are checked against the post's categories' term_ids, names and slugs.
* Categories given as integers will only be checked against the post's categories' term_ids.
*
* If no categories are given, determines if post has any categories.
*
* @since 3.1.0
*
* @param string|int|array $category Optional. The category name/term_id/slug,
* or an array of them to check for. Default empty.
* @param int|WP_Post $post Optional. Post to check. Defaults to the current post.
* @return bool True if the current post has any of the given categories
* (or any category, if no category specified). False otherwise.
*/
function has_category( $category = '', $post = null ) {
return has_term( $category, 'category', $post );
}
/**
* Checks if the current post has any of given tags.
*
* The given tags are checked against the post's tags' term_ids, names and slugs.
* Tags given as integers will only be checked against the post's tags' term_ids.
*
* If no tags are given, determines if post has any tags.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 2.6.0
* @since 2.7.0 Tags given as integers are only checked against
* the post's tags' term_ids, not names or slugs.
* @since 2.7.0 Can be used outside of the WordPress Loop if `$post` is provided.
*
* @param string|int|array $tag Optional. The tag name/term_id/slug,
* or an array of them to check for. Default empty.
* @param int|WP_Post $post Optional. Post to check. Defaults to the current post.
* @return bool True if the current post has any of the given tags
* (or any tag, if no tag specified). False otherwise.
*/
function has_tag( $tag = '', $post = null ) {
return has_term( $tag, 'post_tag', $post );
}
/**
* Checks if the current post has any of given terms.
*
* The given terms are checked against the post's terms' term_ids, names and slugs.
* Terms given as integers will only be checked against the post's terms' term_ids.
*
* If no terms are given, determines if post has any terms.
*
* @since 3.1.0
*
* @param string|int|array $term Optional. The term name/term_id/slug,
* or an array of them to check for. Default empty.
* @param string $taxonomy Optional. Taxonomy name. Default empty.
* @param int|WP_Post $post Optional. Post to check. Defaults to the current post.
* @return bool True if the current post has any of the given terms
* (or any term, if no term specified). False otherwise.
*/
function has_term( $term = '', $taxonomy = '', $post = null ) {
$post = get_post( $post );
if ( ! $post ) {
return false;
}
$r = is_object_in_term( $post->ID, $taxonomy, $term );
if ( is_wp_error( $r ) ) {
return false;
}
return $r;
}
<?php
/**
* Meta API: WP_Meta_Query class
*
* @package WordPress
* @subpackage Meta
* @since 4.4.0
*/
/**
* Core class used to implement meta queries for the Meta API.
*
* Used for generating SQL clauses that filter a primary query according to metadata keys and values.
*
* WP_Meta_Query is a helper that allows primary query classes, such as WP_Query and WP_User_Query,
*
* to filter their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be attached
* to the primary SQL query string.
*
* @since 3.2.0
*/
#[AllowDynamicProperties]
class WP_Meta_Query {
/**
* Array of metadata queries.
*
* See WP_Meta_Query::__construct() for information on meta query arguments.
*
* @since 3.2.0
* @var array
*/
public $queries = array();
/**
* The relation between the queries. Can be one of 'AND' or 'OR'.
*
* @since 3.2.0
* @var string
*/
public $relation;
/**
* Database table to query for the metadata.
*
* @since 4.1.0
* @var string
*/
public $meta_table;
/**
* Column in meta_table that represents the ID of the object the metadata belongs to.
*
* @since 4.1.0
* @var string
*/
public $meta_id_column;
/**
* Database table that where the metadata's objects are stored (eg $wpdb->users).
*
* @since 4.1.0
* @var string
*/
public $primary_table;
/**
* Column in primary_table that represents the ID of the object.
*
* @since 4.1.0
* @var string
*/
public $primary_id_column;
/**
* A flat list of table aliases used in JOIN clauses.
*
* @since 4.1.0
* @var array
*/
protected $table_aliases = array();
/**
* A flat list of clauses, keyed by clause 'name'.
*
* @since 4.2.0
* @var array
*/
protected $clauses = array();
/**
* Whether the query contains any OR relations.
*
* @since 4.3.0
* @var bool
*/
protected $has_or_relation = false;
/**
* Constructor.
*
* @since 3.2.0
* @since 4.2.0 Introduced support for naming query clauses by associative array keys.
* @since 5.1.0 Introduced `$compare_key` clause parameter, which enables LIKE key matches.
* @since 5.3.0 Increased the number of operators available to `$compare_key`. Introduced `$type_key`,
* which enables the `$key` to be cast to a new data type for comparisons.
*
* @param array $meta_query {
* Array of meta query clauses. When first-order clauses or sub-clauses use strings as
* their array keys, they may be referenced in the 'orderby' parameter of the parent query.
*
* @type string $relation Optional. The MySQL keyword used to join the clauses of the query.
* Accepts 'AND' or 'OR'. Default 'AND'.
* @type array ...$0 {
* Optional. An array of first-order clause parameters, or another fully-formed meta query.
*
* @type string|string[] $key Meta key or keys to filter by.
* @type string $compare_key MySQL operator used for comparing the $key. Accepts:
* - '='
* - '!='
* - 'LIKE'
* - 'NOT LIKE'
* - 'IN'
* - 'NOT IN'
* - 'REGEXP'
* - 'NOT REGEXP'
* - 'RLIKE'
* - 'EXISTS' (alias of '=')
* - 'NOT EXISTS' (alias of '!=')
* Default is 'IN' when `$key` is an array, '=' otherwise.
* @type string $type_key MySQL data type that the meta_key column will be CAST to for
* comparisons. Accepts 'BINARY' for case-sensitive regular expression
* comparisons. Default is ''.
* @type string|string[] $value Meta value or values to filter by.
* @type string $compare MySQL operator used for comparing the $value. Accepts:
* - '='
* - '!='
* - '>'
* - '>='
* - '<'
* - '<='
* - 'LIKE'
* - 'NOT LIKE'
* - 'IN'
* - 'NOT IN'
* - 'BETWEEN'
* - 'NOT BETWEEN'
* - 'REGEXP'
* - 'NOT REGEXP'
* - 'RLIKE'
* - 'EXISTS'
* - 'NOT EXISTS'
* Default is 'IN' when `$value` is an array, '=' otherwise.
* @type string $type MySQL data type that the meta_value column will be CAST to for
* comparisons. Accepts:
* - 'NUMERIC'
* - 'BINARY'
* - 'CHAR'
* - 'DATE'
* - 'DATETIME'
* - 'DECIMAL'
* - 'SIGNED'
* - 'TIME'
* - 'UNSIGNED'
* Default is 'CHAR'.
* }
* }
*/
public function __construct( $meta_query = false ) {
if ( ! $meta_query ) {
return;
}
if ( isset( $meta_query['relation'] ) && 'OR' === strtoupper( $meta_query['relation'] ) ) {
$this->relation = 'OR';
} else {
$this->relation = 'AND';
}
$this->queries = $this->sanitize_query( $meta_query );
}
/**
* Ensures the 'meta_query' argument passed to the class constructor is well-formed.
*
* Eliminates empty items and ensures that a 'relation' is set.
*
* @since 4.1.0
*
* @param array $queries Array of query clauses.
* @return array Sanitized array of query clauses.
*/
public function sanitize_query( $queries ) {
$clean_queries = array();
if ( ! is_array( $queries ) ) {
return $clean_queries;
}
foreach ( $queries as $key => $query ) {
if ( 'relation' === $key ) {
$relation = $query;
} elseif ( ! is_array( $query ) ) {
continue;
// First-order clause.
} elseif ( $this->is_first_order_clause( $query ) ) {
if ( isset( $query['value'] ) && array() === $query['value'] ) {
unset( $query['value'] );
}
$clean_queries[ $key ] = $query;
// Otherwise, it's a nested query, so we recurse.
} else {
$cleaned_query = $this->sanitize_query( $query );
if ( ! empty( $cleaned_query ) ) {
$clean_queries[ $key ] = $cleaned_query;
}
}
}
if ( empty( $clean_queries ) ) {
return $clean_queries;
}
// Sanitize the 'relation' key provided in the query.
if ( isset( $relation ) && 'OR' === strtoupper( $relation ) ) {
$clean_queries['relation'] = 'OR';
$this->has_or_relation = true;
/*
* If there is only a single clause, call the relation 'OR'.
* This value will not actually be used to join clauses, but it
* simplifies the logic around combining key-only queries.
*/
} elseif ( 1 === count( $clean_queries ) ) {
$clean_queries['relation'] = 'OR';
// Default to AND.
} else {
$clean_queries['relation'] = 'AND';
}
return $clean_queries;
}
/**
* Determines whether a query clause is first-order.
*
* A first-order meta query clause is one that has either a 'key' or
* a 'value' array key.
*
* @since 4.1.0
*
* @param array $query Meta query arguments.
* @return bool Whether the query clause is a first-order clause.
*/
protected function is_first_order_clause( $query ) {
return isset( $query['key'] ) || isset( $query['value'] );
}
/**
* Constructs a meta query based on 'meta_*' query vars
*
* @since 3.2.0
*
* @param array $qv The query variables.
*/
public function parse_query_vars( $qv ) {
$meta_query = array();
/*
* For orderby=meta_value to work correctly, simple query needs to be
* first (so that its table join is against an unaliased meta table) and
* needs to be its own clause (so it doesn't interfere with the logic of
* the rest of the meta_query).
*/
$primary_meta_query = array();
foreach ( array( 'key', 'compare', 'type', 'compare_key', 'type_key' ) as $key ) {
if ( ! empty( $qv[ "meta_$key" ] ) ) {
$primary_meta_query[ $key ] = $qv[ "meta_$key" ];
}
}
// WP_Query sets 'meta_value' = '' by default.
if ( isset( $qv['meta_value'] ) && '' !== $qv['meta_value'] && ( ! is_array( $qv['meta_value'] ) || $qv['meta_value'] ) ) {
$primary_meta_query['value'] = $qv['meta_value'];
}
$existing_meta_query = isset( $qv['meta_query'] ) && is_array( $qv['meta_query'] ) ? $qv['meta_query'] : array();
if ( ! empty( $primary_meta_query ) && ! empty( $existing_meta_query ) ) {
$meta_query = array(
'relation' => 'AND',
$primary_meta_query,
$existing_meta_query,
);
} elseif ( ! empty( $primary_meta_query ) ) {
$meta_query = array(
$primary_meta_query,
);
} elseif ( ! empty( $existing_meta_query ) ) {
$meta_query = $existing_meta_query;
}
$this->__construct( $meta_query );
}
/**
* Returns the appropriate alias for the given meta type if applicable.
*
* @since 3.7.0
*
* @param string $type MySQL type to cast meta_value.
* @return string MySQL type.
*/
public function get_cast_for_type( $type = '' ) {
if ( empty( $type ) ) {
return 'CHAR';
}
$meta_type = strtoupper( $type );
if ( ! preg_match( '/^(?:BINARY|CHAR|DATE|DATETIME|SIGNED|UNSIGNED|TIME|NUMERIC(?:\(\d+(?:,\s?\d+)?\))?|DECIMAL(?:\(\d+(?:,\s?\d+)?\))?)$/', $meta_type ) ) {
return 'CHAR';
}
if ( 'NUMERIC' === $meta_type ) {
$meta_type = 'SIGNED';
}
return $meta_type;
}
/**
* Generates SQL clauses to be appended to a main query.
*
* @since 3.2.0
*
* @param string $type Type of meta. Possible values include but are not limited
* to 'post', 'comment', 'blog', 'term', and 'user'.
* @param string $primary_table Database table where the object being filtered is stored (eg wp_users).
* @param string $primary_id_column ID column for the filtered object in $primary_table.
* @param object $context Optional. The main query object that corresponds to the type, for
* example a `WP_Query`, `WP_User_Query`, or `WP_Site_Query`.
* Default null.
* @return string[]|false {
* Array containing JOIN and WHERE SQL clauses to append to the main query,
* or false if no table exists for the requested meta type.
*
* @type string $join SQL fragment to append to the main JOIN clause.
* @type string $where SQL fragment to append to the main WHERE clause.
* }
*/
public function get_sql( $type, $primary_table, $primary_id_column, $context = null ) {
$meta_table = _get_meta_table( $type );
if ( ! $meta_table ) {
return false;
}
$this->table_aliases = array();
$this->meta_table = $meta_table;
$this->meta_id_column = sanitize_key( $type . '_id' );
$this->primary_table = $primary_table;
$this->primary_id_column = $primary_id_column;
$sql = $this->get_sql_clauses();
/*
* If any JOINs are LEFT JOINs (as in the case of NOT EXISTS), then all JOINs should
* be LEFT. Otherwise posts with no metadata will be excluded from results.
*/
if ( str_contains( $sql['join'], 'LEFT JOIN' ) ) {
$sql['join'] = str_replace( 'INNER JOIN', 'LEFT JOIN', $sql['join'] );
}
/**
* Filters the meta query's generated SQL.
*
* @since 3.1.0
*
* @param string[] $sql Array containing the query's JOIN and WHERE clauses.
* @param array $queries Array of meta queries.
* @param string $type Type of meta. Possible values include but are not limited
* to 'post', 'comment', 'blog', 'term', and 'user'.
* @param string $primary_table Primary table.
* @param string $primary_id_column Primary column ID.
* @param object $context The main query object that corresponds to the type, for
* example a `WP_Query`, `WP_User_Query`, or `WP_Site_Query`.
*/
return apply_filters_ref_array( 'get_meta_sql', array( $sql, $this->queries, $type, $primary_table, $primary_id_column, $context ) );
}
/**
* Generates SQL clauses to be appended to a main query.
*
* Called by the public WP_Meta_Query::get_sql(), this method is abstracted
* out to maintain parity with the other Query classes.
*
* @since 4.1.0
*
* @return string[] {
* Array containing JOIN and WHERE SQL clauses to append to the main query.
*
* @type string $join SQL fragment to append to the main JOIN clause.
* @type string $where SQL fragment to append to the main WHERE clause.
* }
*/
protected function get_sql_clauses() {
/*
* $queries are passed by reference to get_sql_for_query() for recursion.
* To keep $this->queries unaltered, pass a copy.
*/
$queries = $this->queries;
$sql = $this->get_sql_for_query( $queries );
if ( ! empty( $sql['where'] ) ) {
$sql['where'] = ' AND ' . $sql['where'];
}
return $sql;
}
/**
* Generates SQL clauses for a single query array.
*
* If nested subqueries are found, this method recurses the tree to
* produce the properly nested SQL.
*
* @since 4.1.0
*
* @param array $query Query to parse (passed by reference).
* @param int $depth Optional. Number of tree levels deep we currently are.
* Used to calculate indentation. Default 0.
* @return string[] {
* Array containing JOIN and WHERE SQL clauses to append to a single query array.
*
* @type string $join SQL fragment to append to the main JOIN clause.
* @type string $where SQL fragment to append to the main WHERE clause.
* }
*/
protected function get_sql_for_query( &$query, $depth = 0 ) {
$sql_chunks = array(
'join' => array(),
'where' => array(),
);
$sql = array(
'join' => '',
'where' => '',
);
$indent = '';
for ( $i = 0; $i < $depth; $i++ ) {
$indent .= ' ';
}
foreach ( $query as $key => &$clause ) {
if ( 'relation' === $key ) {
$relation = $query['relation'];
} elseif ( is_array( $clause ) ) {
// This is a first-order clause.
if ( $this->is_first_order_clause( $clause ) ) {
$clause_sql = $this->get_sql_for_clause( $clause, $query, $key );
$where_count = count( $clause_sql['where'] );
if ( ! $where_count ) {
$sql_chunks['where'][] = '';
} elseif ( 1 === $where_count ) {
$sql_chunks['where'][] = $clause_sql['where'][0];
} else {
$sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )';
}
$sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] );
// This is a subquery, so we recurse.
} else {
$clause_sql = $this->get_sql_for_query( $clause, $depth + 1 );
$sql_chunks['where'][] = $clause_sql['where'];
$sql_chunks['join'][] = $clause_sql['join'];
}
}
}
// Filter to remove empties.
$sql_chunks['join'] = array_filter( $sql_chunks['join'] );
$sql_chunks['where'] = array_filter( $sql_chunks['where'] );
if ( empty( $relation ) ) {
$relation = 'AND';
}
// Filter duplicate JOIN clauses and combine into a single string.
if ( ! empty( $sql_chunks['join'] ) ) {
$sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) );
}
// Generate a single WHERE clause with proper brackets and indentation.
if ( ! empty( $sql_chunks['where'] ) ) {
$sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')';
}
return $sql;
}
/**
* Generates SQL JOIN and WHERE clauses for a first-order query clause.
*
* "First-order" means that it's an array with a 'key' or 'value'.
*
* @since 4.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param array $clause Query clause (passed by reference).
* @param array $parent_query Parent query array.
* @param string $clause_key Optional. The array key used to name the clause in the original `$meta_query`
* parameters. If not provided, a key will be generated automatically.
* Default empty string.
* @return array {
* Array containing JOIN and WHERE SQL clauses to append to a first-order query.
*
* @type string[] $join Array of SQL fragments to append to the main JOIN clause.
* @type string[] $where Array of SQL fragments to append to the main WHERE clause.
* }
*/
public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' ) {
global $wpdb;
$sql_chunks = array(
'where' => array(),
'join' => array(),
);
if ( isset( $clause['compare'] ) ) {
$clause['compare'] = strtoupper( $clause['compare'] );
} else {
$clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
}
$non_numeric_operators = array(
'=',
'!=',
'LIKE',
'NOT LIKE',
'IN',
'NOT IN',
'EXISTS',
'NOT EXISTS',
'RLIKE',
'REGEXP',
'NOT REGEXP',
);
$numeric_operators = array(
'>',
'>=',
'<',
'<=',
'BETWEEN',
'NOT BETWEEN',
);
if ( ! in_array( $clause['compare'], $non_numeric_operators, true ) && ! in_array( $clause['compare'], $numeric_operators, true ) ) {
$clause['compare'] = '=';
}
if ( isset( $clause['compare_key'] ) ) {
$clause['compare_key'] = strtoupper( $clause['compare_key'] );
} else {
$clause['compare_key'] = isset( $clause['key'] ) && is_array( $clause['key'] ) ? 'IN' : '=';
}
if ( ! in_array( $clause['compare_key'], $non_numeric_operators, true ) ) {
$clause['compare_key'] = '=';
}
$meta_compare = $clause['compare'];
$meta_compare_key = $clause['compare_key'];
// First build the JOIN clause, if one is required.
$join = '';
// We prefer to avoid joins if possible. Look for an existing join compatible with this clause.
$alias = $this->find_compatible_table_alias( $clause, $parent_query );
if ( false === $alias ) {
$i = count( $this->table_aliases );
$alias = $i ? 'mt' . $i : $this->meta_table;
// JOIN clauses for NOT EXISTS have their own syntax.
if ( 'NOT EXISTS' === $meta_compare ) {
$join .= " LEFT JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
if ( 'LIKE' === $meta_compare_key ) {
$join .= $wpdb->prepare( " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key LIKE %s )", '%' . $wpdb->esc_like( $clause['key'] ) . '%' );
} else {
$join .= $wpdb->prepare( " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key = %s )", $clause['key'] );
}
// All other JOIN clauses.
} else {
$join .= " INNER JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
$join .= " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column )";
}
$this->table_aliases[] = $alias;
$sql_chunks['join'][] = $join;
}
// Save the alias to this clause, for future siblings to find.
$clause['alias'] = $alias;
// Determine the data type.
$_meta_type = isset( $clause['type'] ) ? $clause['type'] : '';
$meta_type = $this->get_cast_for_type( $_meta_type );
$clause['cast'] = $meta_type;
// Fallback for clause keys is the table alias. Key must be a string.
if ( is_int( $clause_key ) || ! $clause_key ) {
$clause_key = $clause['alias'];
}
// Ensure unique clause keys, so none are overwritten.
$iterator = 1;
$clause_key_base = $clause_key;
while ( isset( $this->clauses[ $clause_key ] ) ) {
$clause_key = $clause_key_base . '-' . $iterator;
++$iterator;
}
// Store the clause in our flat array.
$this->clauses[ $clause_key ] =& $clause;
// Next, build the WHERE clause.
// meta_key.
if ( array_key_exists( 'key', $clause ) ) {
if ( 'NOT EXISTS' === $meta_compare ) {
$sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
} else {
/**
* In joined clauses negative operators have to be nested into a
* NOT EXISTS clause and flipped, to avoid returning records with
* matching post IDs but different meta keys. Here we prepare the
* nested clause.
*/
if ( in_array( $meta_compare_key, array( '!=', 'NOT IN', 'NOT LIKE', 'NOT EXISTS', 'NOT REGEXP' ), true ) ) {
// Negative clauses may be reused.
$i = count( $this->table_aliases );
$subquery_alias = $i ? 'mt' . $i : $this->meta_table;
$this->table_aliases[] = $subquery_alias;
$meta_compare_string_start = 'NOT EXISTS (';
$meta_compare_string_start .= "SELECT 1 FROM $wpdb->postmeta $subquery_alias ";
$meta_compare_string_start .= "WHERE $subquery_alias.post_ID = $alias.post_ID ";
$meta_compare_string_end = 'LIMIT 1';
$meta_compare_string_end .= ')';
}
switch ( $meta_compare_key ) {
case '=':
case 'EXISTS':
$where = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
break;
case 'LIKE':
$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
$where = $wpdb->prepare( "$alias.meta_key LIKE %s", $meta_compare_value ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
break;
case 'IN':
$meta_compare_string = "$alias.meta_key IN (" . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ')';
$where = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
break;
case 'RLIKE':
case 'REGEXP':
$operator = $meta_compare_key;
if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) {
$cast = 'BINARY';
$meta_key = "CAST($alias.meta_key AS BINARY)";
} else {
$cast = '';
$meta_key = "$alias.meta_key";
}
$where = $wpdb->prepare( "$meta_key $operator $cast %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
break;
case '!=':
case 'NOT EXISTS':
$meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key = %s " . $meta_compare_string_end;
$where = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
break;
case 'NOT LIKE':
$meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key LIKE %s " . $meta_compare_string_end;
$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
$where = $wpdb->prepare( $meta_compare_string, $meta_compare_value ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
break;
case 'NOT IN':
$array_subclause = '(' . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ') ';
$meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key IN " . $array_subclause . $meta_compare_string_end;
$where = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
break;
case 'NOT REGEXP':
$operator = $meta_compare_key;
if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) {
$cast = 'BINARY';
$meta_key = "CAST($subquery_alias.meta_key AS BINARY)";
} else {
$cast = '';
$meta_key = "$subquery_alias.meta_key";
}
$meta_compare_string = $meta_compare_string_start . "AND $meta_key REGEXP $cast %s " . $meta_compare_string_end;
$where = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
break;
}
$sql_chunks['where'][] = $where;
}
}
// meta_value.
if ( array_key_exists( 'value', $clause ) ) {
$meta_value = $clause['value'];
if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ), true ) ) {
if ( ! is_array( $meta_value ) ) {
$meta_value = preg_split( '/[,\s]+/', $meta_value );
}
} elseif ( is_string( $meta_value ) ) {
$meta_value = trim( $meta_value );
}
switch ( $meta_compare ) {
case 'IN':
case 'NOT IN':
$meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
$where = $wpdb->prepare( $meta_compare_string, $meta_value );
break;
case 'BETWEEN':
case 'NOT BETWEEN':
$where = $wpdb->prepare( '%s AND %s', $meta_value[0], $meta_value[1] );
break;
case 'LIKE':
case 'NOT LIKE':
$meta_value = '%' . $wpdb->esc_like( $meta_value ) . '%';
$where = $wpdb->prepare( '%s', $meta_value );
break;
// EXISTS with a value is interpreted as '='.
case 'EXISTS':
$meta_compare = '=';
$where = $wpdb->prepare( '%s', $meta_value );
break;
// 'value' is ignored for NOT EXISTS.
case 'NOT EXISTS':
$where = '';
break;
default:
$where = $wpdb->prepare( '%s', $meta_value );
break;
}
if ( $where ) {
if ( 'CHAR' === $meta_type ) {
$sql_chunks['where'][] = "$alias.meta_value {$meta_compare} {$where}";
} else {
$sql_chunks['where'][] = "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$where}";
}
}
}
/*
* Multiple WHERE clauses (for meta_key and meta_value) should
* be joined in parentheses.
*/
if ( 1 < count( $sql_chunks['where'] ) ) {
$sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' );
}
return $sql_chunks;
}
/**
* Gets a flattened list of sanitized meta clauses.
*
* This array should be used for clause lookup, as when the table alias and CAST type must be determined for
* a value of 'orderby' corresponding to a meta clause.
*
* @since 4.2.0
*
* @return array Meta clauses.
*/
public function get_clauses() {
return $this->clauses;
}
/**
* Identifies an existing table alias that is compatible with the current
* query clause.
*
* We avoid unnecessary table joins by allowing each clause to look for
* an existing table alias that is compatible with the query that it
* needs to perform.
*
* An existing alias is compatible if (a) it is a sibling of `$clause`
* (ie, it's under the scope of the same relation), and (b) the combination
* of operator and relation between the clauses allows for a shared table join.
* In the case of WP_Meta_Query, this only applies to 'IN' clauses that are
* connected by the relation 'OR'.
*
* @since 4.1.0
*
* @param array $clause Query clause.
* @param array $parent_query Parent query of $clause.
* @return string|false Table alias if found, otherwise false.
*/
protected function find_compatible_table_alias( $clause, $parent_query ) {
$alias = false;
foreach ( $parent_query as $sibling ) {
// If the sibling has no alias yet, there's nothing to check.
if ( empty( $sibling['alias'] ) ) {
continue;
}
// We're only interested in siblings that are first-order clauses.
if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
continue;
}
$compatible_compares = array();
// Clauses connected by OR can share joins as long as they have "positive" operators.
if ( 'OR' === $parent_query['relation'] ) {
$compatible_compares = array( '=', 'IN', 'BETWEEN', 'LIKE', 'REGEXP', 'RLIKE', '>', '>=', '<', '<=' );
// Clauses joined by AND with "negative" operators share a join only if they also share a key.
} elseif ( isset( $sibling['key'] ) && isset( $clause['key'] ) && $sibling['key'] === $clause['key'] ) {
$compatible_compares = array( '!=', 'NOT IN', 'NOT LIKE' );
}
$clause_compare = strtoupper( $clause['compare'] );
$sibling_compare = strtoupper( $sibling['compare'] );
if ( in_array( $clause_compare, $compatible_compares, true ) && in_array( $sibling_compare, $compatible_compares, true ) ) {
$alias = preg_replace( '/\W/', '_', $sibling['alias'] );
break;
}
}
/**
* Filters the table alias identified as compatible with the current clause.
*
* @since 4.1.0
*
* @param string|false $alias Table alias, or false if none was found.
* @param array $clause First-order query clause.
* @param array $parent_query Parent of $clause.
* @param WP_Meta_Query $query WP_Meta_Query object.
*/
return apply_filters( 'meta_query_find_compatible_table_alias', $alias, $clause, $parent_query, $this );
}
/**
* Checks whether the current query has any OR relations.
*
* In some cases, the presence of an OR relation somewhere in the query will require
* the use of a `DISTINCT` or `GROUP BY` keyword in the `SELECT` clause. The current
* method can be used in these cases to determine whether such a clause is necessary.
*
* @since 4.3.0
*
* @return bool True if the query contains any `OR` relations, otherwise false.
*/
public function has_or_relation() {
return $this->has_or_relation;
}
}
<?php
/**
* Author Template functions for use in themes.
*
* These functions must be used within the WordPress Loop.
*
* @link https://codex.wordpress.org/Author_Templates
*
* @package WordPress
* @subpackage Template
*/
/**
* Retrieves the author of the current post.
*
* @since 1.5.0
* @since 6.3.0 Returns an empty string if the author's display name is unknown.
*
* @global WP_User $authordata The current author's data.
*
* @param string $deprecated Deprecated.
* @return string The author's display name, empty string if unknown.
*/
function get_the_author( $deprecated = '' ) {
global $authordata;
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.1.0' );
}
/**
* Filters the display name of the current post's author.
*
* @since 2.9.0
*
* @param string $display_name The author's display name.
*/
return apply_filters( 'the_author', is_object( $authordata ) ? $authordata->display_name : '' );
}
/**
* Displays the name of the author of the current post.
*
* The behavior of this function is based off of old functionality predating
* get_the_author(). This function is not deprecated, but is designed to echo
* the value from get_the_author() and as an result of any old theme that might
* still use the old behavior will also pass the value from get_the_author().
*
* The normal, expected behavior of this function is to echo the author and not
* return it. However, backward compatibility has to be maintained.
*
* @since 0.71
*
* @see get_the_author()
* @link https://developer.wordpress.org/reference/functions/the_author/
*
* @param string $deprecated Deprecated.
* @param bool $deprecated_echo Deprecated. Use get_the_author(). Echo the string or return it.
* @return string The author's display name, from get_the_author().
*/
function the_author( $deprecated = '', $deprecated_echo = true ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.1.0' );
}
if ( true !== $deprecated_echo ) {
_deprecated_argument(
__FUNCTION__,
'1.5.0',
sprintf(
/* translators: %s: get_the_author() */
__( 'Use %s instead if you do not want the value echoed.' ),
'<code>get_the_author()</code>'
)
);
}
if ( $deprecated_echo ) {
echo get_the_author();
}
return get_the_author();
}
/**
* Retrieves the author who last edited the current post.
*
* @since 2.8.0
*
* @return string|void The author's display name, empty string if unknown.
*/
function get_the_modified_author() {
$last_id = get_post_meta( get_post()->ID, '_edit_last', true );
if ( $last_id ) {
$last_user = get_userdata( $last_id );
/**
* Filters the display name of the author who last edited the current post.
*
* @since 2.8.0
*
* @param string $display_name The author's display name, empty string if unknown.
*/
return apply_filters( 'the_modified_author', $last_user ? $last_user->display_name : '' );
}
}
/**
* Displays the name of the author who last edited the current post,
* if the author's ID is available.
*
* @since 2.8.0
*
* @see get_the_author()
*/
function the_modified_author() {
echo get_the_modified_author();
}
/**
* Retrieves the requested data of the author of the current post.
*
* Valid values for the `$field` parameter include:
*
* - admin_color
* - aim
* - comment_shortcuts
* - description
* - display_name
* - first_name
* - ID
* - jabber
* - last_name
* - nickname
* - plugins_last_view
* - plugins_per_page
* - rich_editing
* - syntax_highlighting
* - user_activation_key
* - user_description
* - user_email
* - user_firstname
* - user_lastname
* - user_level
* - user_login
* - user_nicename
* - user_pass
* - user_registered
* - user_status
* - user_url
* - yim
*
* @since 2.8.0
*
* @global WP_User $authordata The current author's data.
*
* @param string $field Optional. The user field to retrieve. Default empty.
* @param int|false $user_id Optional. User ID. Defaults to the current post author.
* @return string The author's field from the current author's DB object, otherwise an empty string.
*/
function get_the_author_meta( $field = '', $user_id = false ) {
$original_user_id = $user_id;
if ( ! $user_id ) {
global $authordata;
$user_id = isset( $authordata->ID ) ? $authordata->ID : 0;
} else {
$authordata = get_userdata( $user_id );
}
if ( in_array( $field, array( 'login', 'pass', 'nicename', 'email', 'url', 'registered', 'activation_key', 'status' ), true ) ) {
$field = 'user_' . $field;
}
$value = isset( $authordata->$field ) ? $authordata->$field : '';
/**
* Filters the value of the requested user metadata.
*
* The filter name is dynamic and depends on the $field parameter of the function.
*
* @since 2.8.0
* @since 4.3.0 The `$original_user_id` parameter was added.
*
* @param string $value The value of the metadata.
* @param int $user_id The user ID for the value.
* @param int|false $original_user_id The original user ID, as passed to the function.
*/
return apply_filters( "get_the_author_{$field}", $value, $user_id, $original_user_id );
}
/**
* Outputs the field from the user's DB object. Defaults to current post's author.
*
* @since 2.8.0
*
* @param string $field Selects the field of the users record. See get_the_author_meta()
* for the list of possible fields.
* @param int|false $user_id Optional. User ID. Defaults to the current post author.
*
* @see get_the_author_meta()
*/
function the_author_meta( $field = '', $user_id = false ) {
$author_meta = get_the_author_meta( $field, $user_id );
/**
* Filters the value of the requested user metadata.
*
* The filter name is dynamic and depends on the $field parameter of the function.
*
* @since 2.8.0
*
* @param string $author_meta The value of the metadata.
* @param int|false $user_id The user ID.
*/
echo apply_filters( "the_author_{$field}", $author_meta, $user_id );
}
/**
* Retrieves either author's link or author's name.
*
* If the author has a home page set, return an HTML link, otherwise just return
* the author's name.
*
* @since 3.0.0
*
* @global WP_User $authordata The current author's data.
*
* @return string An HTML link if the author's URL exists in user meta,
* otherwise the result of get_the_author().
*/
function get_the_author_link() {
if ( get_the_author_meta( 'url' ) ) {
global $authordata;
$author_url = get_the_author_meta( 'url' );
$author_display_name = get_the_author();
$link = sprintf(
'<a href="%1$s" title="%2$s" rel="author external">%3$s</a>',
esc_url( $author_url ),
/* translators: %s: Author's display name. */
esc_attr( sprintf( __( 'Visit %s’s website' ), $author_display_name ) ),
$author_display_name
);
/**
* Filters the author URL link HTML.
*
* @since 6.0.0
*
* @param string $link The default rendered author HTML link.
* @param string $author_url Author's URL.
* @param WP_User $authordata Author user data.
*/
return apply_filters( 'the_author_link', $link, $author_url, $authordata );
} else {
return get_the_author();
}
}
/**
* Displays either author's link or author's name.
*
* If the author has a home page set, echo an HTML link, otherwise just echo the
* author's name.
*
* @link https://developer.wordpress.org/reference/functions/the_author_link/
*
* @since 2.1.0
*/
function the_author_link() {
echo get_the_author_link();
}
/**
* Retrieves the number of posts by the author of the current post.
*
* @since 1.5.0
*
* @return int The number of posts by the author.
*/
function get_the_author_posts() {
$post = get_post();
if ( ! $post ) {
return 0;
}
return count_user_posts( $post->post_author, $post->post_type );
}
/**
* Displays the number of posts by the author of the current post.
*
* @link https://developer.wordpress.org/reference/functions/the_author_posts/
* @since 0.71
*/
function the_author_posts() {
echo get_the_author_posts();
}
/**
* Retrieves an HTML link to the author page of the current post's author.
*
* Returns an HTML-formatted link using get_author_posts_url().
*
* @since 4.4.0
*
* @global WP_User $authordata The current author's data.
*
* @return string An HTML link to the author page, or an empty string if $authordata is not set.
*/
function get_the_author_posts_link() {
global $authordata;
if ( ! is_object( $authordata ) ) {
return '';
}
$link = sprintf(
'<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ),
/* translators: %s: Author's display name. */
esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
get_the_author()
);
/**
* Filters the link to the author page of the author of the current post.
*
* @since 2.9.0
*
* @param string $link HTML link.
*/
return apply_filters( 'the_author_posts_link', $link );
}
/**
* Displays an HTML link to the author page of the current post's author.
*
* @since 1.2.0
* @since 4.4.0 Converted into a wrapper for get_the_author_posts_link()
*
* @param string $deprecated Unused.
*/
function the_author_posts_link( $deprecated = '' ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.1.0' );
}
echo get_the_author_posts_link();
}
/**
* Retrieves the URL to the author page for the user with the ID provided.
*
* @since 2.1.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int $author_id Author ID.
* @param string $author_nicename Optional. The author's nicename (slug). Default empty.
* @return string The URL to the author's page.
*/
function get_author_posts_url( $author_id, $author_nicename = '' ) {
global $wp_rewrite;
$author_id = (int) $author_id;
$link = $wp_rewrite->get_author_permastruct();
if ( empty( $link ) ) {
$file = home_url( '/' );
$link = $file . '?author=' . $author_id;
} else {
if ( '' === $author_nicename ) {
$user = get_userdata( $author_id );
if ( ! empty( $user->user_nicename ) ) {
$author_nicename = $user->user_nicename;
}
}
$link = str_replace( '%author%', $author_nicename, $link );
$link = home_url( user_trailingslashit( $link ) );
}
/**
* Filters the URL to the author's page.
*
* @since 2.1.0
*
* @param string $link The URL to the author's page.
* @param int $author_id The author's ID.
* @param string $author_nicename The author's nice name.
*/
$link = apply_filters( 'author_link', $link, $author_id, $author_nicename );
return $link;
}
/**
* Lists all the authors of the site, with several options available.
*
* @link https://developer.wordpress.org/reference/functions/wp_list_authors/
*
* @since 1.2.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string|array $args {
* Optional. Array or string of default arguments.
*
* @type string $orderby How to sort the authors. Accepts 'nicename', 'email', 'url', 'registered',
* 'user_nicename', 'user_email', 'user_url', 'user_registered', 'name',
* 'display_name', 'post_count', 'ID', 'meta_value', 'user_login'. Default 'name'.
* @type string $order Sorting direction for $orderby. Accepts 'ASC', 'DESC'. Default 'ASC'.
* @type int $number Maximum authors to return or display. Default empty (all authors).
* @type bool $optioncount Show the count in parenthesis next to the author's name. Default false.
* @type bool $exclude_admin Whether to exclude the 'admin' account, if it exists. Default true.
* @type bool $show_fullname Whether to show the author's full name. Default false.
* @type bool $hide_empty Whether to hide any authors with no posts. Default true.
* @type string $feed If not empty, show a link to the author's feed and use this text as the alt
* parameter of the link. Default empty.
* @type string $feed_image If not empty, show a link to the author's feed and use this image URL as
* clickable anchor. Default empty.
* @type string $feed_type The feed type to link to. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @type bool $echo Whether to output the result or instead return it. Default true.
* @type string $style If 'list', each author is wrapped in an `<li>` element, otherwise the authors
* will be separated by commas.
* @type bool $html Whether to list the items in HTML form or plaintext. Default true.
* @type int[]|string $exclude Array or comma/space-separated list of author IDs to exclude. Default empty.
* @type int[]|string $include Array or comma/space-separated list of author IDs to include. Default empty.
* }
* @return void|string Void if 'echo' argument is true, list of authors if 'echo' is false.
*/
function wp_list_authors( $args = '' ) {
global $wpdb;
$defaults = array(
'orderby' => 'name',
'order' => 'ASC',
'number' => '',
'optioncount' => false,
'exclude_admin' => true,
'show_fullname' => false,
'hide_empty' => true,
'feed' => '',
'feed_image' => '',
'feed_type' => '',
'echo' => true,
'style' => 'list',
'html' => true,
'exclude' => '',
'include' => '',
);
$parsed_args = wp_parse_args( $args, $defaults );
$return = '';
$query_args = wp_array_slice_assoc( $parsed_args, array( 'orderby', 'order', 'number', 'exclude', 'include' ) );
$query_args['fields'] = 'ids';
/**
* Filters the query arguments for the list of all authors of the site.
*
* @since 6.1.0
*
* @param array $query_args The query arguments for get_users().
* @param array $parsed_args The arguments passed to wp_list_authors() combined with the defaults.
*/
$query_args = apply_filters( 'wp_list_authors_args', $query_args, $parsed_args );
$authors = get_users( $query_args );
$post_counts = array();
/**
* Filters whether to short-circuit performing the query for author post counts.
*
* @since 6.1.0
*
* @param int[]|false $post_counts Array of post counts, keyed by author ID.
* @param array $parsed_args The arguments passed to wp_list_authors() combined with the defaults.
*/
$post_counts = apply_filters( 'pre_wp_list_authors_post_counts_query', false, $parsed_args );
if ( ! is_array( $post_counts ) ) {
$post_counts = array();
$post_counts_query = $wpdb->get_results(
"SELECT DISTINCT post_author, COUNT(ID) AS count
FROM $wpdb->posts
WHERE " . get_private_posts_cap_sql( 'post' ) . '
GROUP BY post_author'
);
foreach ( (array) $post_counts_query as $row ) {
$post_counts[ $row->post_author ] = $row->count;
}
}
foreach ( $authors as $author_id ) {
$posts = isset( $post_counts[ $author_id ] ) ? $post_counts[ $author_id ] : 0;
if ( ! $posts && $parsed_args['hide_empty'] ) {
continue;
}
$author = get_userdata( $author_id );
if ( $parsed_args['exclude_admin'] && 'admin' === $author->display_name ) {
continue;
}
if ( $parsed_args['show_fullname'] && $author->first_name && $author->last_name ) {
$name = sprintf(
/* translators: 1: User's first name, 2: Last name. */
_x( '%1$s %2$s', 'Display name based on first name and last name' ),
$author->first_name,
$author->last_name
);
} else {
$name = $author->display_name;
}
if ( ! $parsed_args['html'] ) {
$return .= $name . ', ';
continue; // No need to go further to process HTML.
}
if ( 'list' === $parsed_args['style'] ) {
$return .= '<li>';
}
$link = sprintf(
'<a href="%1$s" title="%2$s">%3$s</a>',
esc_url( get_author_posts_url( $author->ID, $author->user_nicename ) ),
/* translators: %s: Author's display name. */
esc_attr( sprintf( __( 'Posts by %s' ), $author->display_name ) ),
$name
);
if ( ! empty( $parsed_args['feed_image'] ) || ! empty( $parsed_args['feed'] ) ) {
$link .= ' ';
if ( empty( $parsed_args['feed_image'] ) ) {
$link .= '(';
}
$link .= '<a href="' . get_author_feed_link( $author->ID, $parsed_args['feed_type'] ) . '"';
$alt = '';
if ( ! empty( $parsed_args['feed'] ) ) {
$alt = ' alt="' . esc_attr( $parsed_args['feed'] ) . '"';
$name = $parsed_args['feed'];
}
$link .= '>';
if ( ! empty( $parsed_args['feed_image'] ) ) {
$link .= '<img src="' . esc_url( $parsed_args['feed_image'] ) . '" style="border: none;"' . $alt . ' />';
} else {
$link .= $name;
}
$link .= '</a>';
if ( empty( $parsed_args['feed_image'] ) ) {
$link .= ')';
}
}
if ( $parsed_args['optioncount'] ) {
$link .= ' (' . $posts . ')';
}
$return .= $link;
$return .= ( 'list' === $parsed_args['style'] ) ? '</li>' : ', ';
}
$return = rtrim( $return, ', ' );
if ( $parsed_args['echo'] ) {
echo $return;
} else {
return $return;
}
}
/**
* Determines whether this site has more than one author.
*
* Checks to see if more than one author has published posts.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 3.2.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return bool Whether or not we have more than one author
*/
function is_multi_author() {
global $wpdb;
$is_multi_author = get_transient( 'is_multi_author' );
if ( false === $is_multi_author ) {
$rows = (array) $wpdb->get_col( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' LIMIT 2" );
$is_multi_author = 1 < count( $rows ) ? 1 : 0;
set_transient( 'is_multi_author', $is_multi_author );
}
/**
* Filters whether the site has more than one author with published posts.
*
* @since 3.2.0
*
* @param bool $is_multi_author Whether $is_multi_author should evaluate as true.
*/
return apply_filters( 'is_multi_author', (bool) $is_multi_author );
}
/**
* Helper function to clear the cache for number of authors.
*
* @since 3.2.0
* @access private
*/
function __clear_multi_author_cache() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
delete_transient( 'is_multi_author' );
}
<?php
/**
* Blocks API: WP_Block_Styles_Registry class
*
* @package WordPress
* @subpackage Blocks
* @since 5.3.0
*/
/**
* Class used for interacting with block styles.
*
* @since 5.3.0
*/
#[AllowDynamicProperties]
final class WP_Block_Styles_Registry {
/**
* Registered block styles, as `$block_name => $block_style_name => $block_style_properties` multidimensional arrays.
*
* @since 5.3.0
*
* @var array[]
*/
private $registered_block_styles = array();
/**
* Container for the main instance of the class.
*
* @since 5.3.0
*
* @var WP_Block_Styles_Registry|null
*/
private static $instance = null;
/**
* Registers a block style for the given block type.
*
* If the block styles are present in a standalone stylesheet, register it and pass
* its handle as the `style_handle` argument. If the block styles should be inline,
* use the `inline_style` argument. Usually, one of them would be used to pass CSS
* styles. However, you could also skip them and provide CSS styles in any stylesheet
* or with an inline tag.
*
* @since 5.3.0
* @since 6.6.0 Added ability to register style across multiple block types along with theme.json-like style data.
*
* @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-styles/
*
* @param string|string[] $block_name Block type name including namespace or array of namespaced block type names.
* @param array $style_properties {
* Array containing the properties of the style.
*
* @type string $name The identifier of the style used to compute a CSS class.
* @type string $label A human-readable label for the style.
* @type string $inline_style Inline CSS code that registers the CSS class required
* for the style.
* @type string $style_handle The handle to an already registered style that should be
* enqueued in places where block styles are needed.
* @type bool $is_default Whether this is the default style for the block type.
* @type array $style_data Theme.json-like object to generate CSS from.
* }
* @return bool True if the block style was registered with success and false otherwise.
*/
public function register( $block_name, $style_properties ) {
if ( ! is_string( $block_name ) && ! is_array( $block_name ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Block name must be a string or array.' ),
'6.6.0'
);
return false;
}
if ( ! isset( $style_properties['name'] ) || ! is_string( $style_properties['name'] ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Block style name must be a string.' ),
'5.3.0'
);
return false;
}
if ( str_contains( $style_properties['name'], ' ' ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Block style name must not contain any spaces.' ),
'5.9.0'
);
return false;
}
$block_style_name = $style_properties['name'];
$block_names = is_string( $block_name ) ? array( $block_name ) : $block_name;
// Ensure there is a label defined.
if ( empty( $style_properties['label'] ) ) {
$style_properties['label'] = $block_style_name;
}
foreach ( $block_names as $name ) {
if ( ! isset( $this->registered_block_styles[ $name ] ) ) {
$this->registered_block_styles[ $name ] = array();
}
$this->registered_block_styles[ $name ][ $block_style_name ] = $style_properties;
}
return true;
}
/**
* Unregisters a block style of the given block type.
*
* @since 5.3.0
*
* @param string $block_name Block type name including namespace.
* @param string $block_style_name Block style name.
* @return bool True if the block style was unregistered with success and false otherwise.
*/
public function unregister( $block_name, $block_style_name ) {
if ( ! $this->is_registered( $block_name, $block_style_name ) ) {
_doing_it_wrong(
__METHOD__,
/* translators: 1: Block name, 2: Block style name. */
sprintf( __( 'Block "%1$s" does not contain a style named "%2$s".' ), $block_name, $block_style_name ),
'5.3.0'
);
return false;
}
unset( $this->registered_block_styles[ $block_name ][ $block_style_name ] );
return true;
}
/**
* Retrieves the properties of a registered block style for the given block type.
*
* @since 5.3.0
*
* @param string $block_name Block type name including namespace.
* @param string $block_style_name Block style name.
* @return array Registered block style properties.
*/
public function get_registered( $block_name, $block_style_name ) {
if ( ! $this->is_registered( $block_name, $block_style_name ) ) {
return null;
}
return $this->registered_block_styles[ $block_name ][ $block_style_name ];
}
/**
* Retrieves all registered block styles.
*
* @since 5.3.0
*
* @return array[] Array of arrays containing the registered block styles properties grouped by block type.
*/
public function get_all_registered() {
return $this->registered_block_styles;
}
/**
* Retrieves registered block styles for a specific block type.
*
* @since 5.3.0
*
* @param string $block_name Block type name including namespace.
* @return array[] Array whose keys are block style names and whose values are block style properties.
*/
public function get_registered_styles_for_block( $block_name ) {
if ( isset( $this->registered_block_styles[ $block_name ] ) ) {
return $this->registered_block_styles[ $block_name ];
}
return array();
}
/**
* Checks if a block style is registered for the given block type.
*
* @since 5.3.0
*
* @param string $block_name Block type name including namespace.
* @param string $block_style_name Block style name.
* @return bool True if the block style is registered, false otherwise.
*/
public function is_registered( $block_name, $block_style_name ) {
return isset( $this->registered_block_styles[ $block_name ][ $block_style_name ] );
}
/**
* Utility method to retrieve the main instance of the class.
*
* The instance will be created if it does not exist yet.
*
* @since 5.3.0
*
* @return WP_Block_Styles_Registry The main instance.
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
}
<?php
/**
* mail_fetch/setup.php
*
* Copyright (c) 1999-2011 CDI (cdi@thewebmasters.net) All Rights Reserved
* Modified by Philippe Mingo 2001-2009 mingo@rotedic.com
* An RFC 1939 compliant wrapper class for the POP3 protocol.
*
* Licensed under the GNU GPL. For full terms see the file COPYING.
*
* POP3 class
*
* @copyright 1999-2011 The SquirrelMail Project Team
* @license https://opensource.org/licenses/gpl-license.php GNU Public License
* @package plugins
* @subpackage mail_fetch
*/
class POP3 {
var $ERROR = ''; // Error string.
var $TIMEOUT = 60; // Default timeout before giving up on a
// network operation.
var $COUNT = -1; // Mailbox msg count
var $BUFFER = 512; // Socket buffer for socket fgets() calls.
// Per RFC 1939 the returned line a POP3
// server can send is 512 bytes.
var $FP = ''; // The connection to the server's
// file descriptor
var $MAILSERVER = ''; // Set this to hard code the server name
var $DEBUG = FALSE; // set to true to echo pop3
// commands and responses to error_log
// this WILL log passwords!
var $BANNER = ''; // Holds the banner returned by the
// pop server - used for apop()
var $ALLOWAPOP = FALSE; // Allow or disallow apop()
// This must be set to true
// manually
/**
* PHP5 constructor.
*/
function __construct ( $server = '', $timeout = '' ) {
settype($this->BUFFER,"integer");
if( !empty($server) ) {
// Do not allow programs to alter MAILSERVER
// if it is already specified. They can get around
// this if they -really- want to, so don't count on it.
if(empty($this->MAILSERVER))
$this->MAILSERVER = $server;
}
if(!empty($timeout)) {
settype($timeout,"integer");
$this->TIMEOUT = $timeout;
// Extend POP3 request timeout to the specified TIMEOUT property.
if(function_exists("set_time_limit")){
set_time_limit($timeout);
}
}
return true;
}
/**
* PHP4 constructor.
*/
public function POP3( $server = '', $timeout = '' ) {
self::__construct( $server, $timeout );
}
function update_timer () {
// Extend POP3 request timeout to the specified TIMEOUT property.
if(function_exists("set_time_limit")){
set_time_limit($this->TIMEOUT);
}
return true;
}
function connect ($server, $port = 110) {
// Opens a socket to the specified server. Unless overridden,
// port defaults to 110. Returns true on success, false on fail
// If MAILSERVER is set, override $server with its value.
if (!isset($port) || !$port) {$port = 110;}
if(!empty($this->MAILSERVER))
$server = $this->MAILSERVER;
if(empty($server)){
$this->ERROR = "POP3 connect: " . _("No server specified");
unset($this->FP);
return false;
}
$fp = @fsockopen("$server", $port, $errno, $errstr);
if(!$fp) {
$this->ERROR = "POP3 connect: " . _("Error ") . "[$errno] [$errstr]";
unset($this->FP);
return false;
}
socket_set_blocking($fp,-1);
$this->update_timer();
$reply = fgets($fp,$this->BUFFER);
$reply = $this->strip_clf($reply);
if($this->DEBUG)
error_log("POP3 SEND [connect: $server] GOT [$reply]",0);
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 connect: " . _("Error ") . "[$reply]";
unset($this->FP);
return false;
}
$this->FP = $fp;
$this->BANNER = $this->parse_banner($reply);
return true;
}
function user ($user = "") {
// Sends the USER command, returns true or false
if( empty($user) ) {
$this->ERROR = "POP3 user: " . _("no login ID submitted");
return false;
} elseif(!isset($this->FP)) {
$this->ERROR = "POP3 user: " . _("connection not established");
return false;
} else {
$reply = $this->send_cmd("USER $user");
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 user: " . _("Error ") . "[$reply]";
return false;
} else
return true;
}
}
function pass ($pass = "") {
// Sends the PASS command, returns # of msgs in mailbox,
// returns false (undef) on Auth failure
if(empty($pass)) {
$this->ERROR = "POP3 pass: " . _("No password submitted");
return false;
} elseif(!isset($this->FP)) {
$this->ERROR = "POP3 pass: " . _("connection not established");
return false;
} else {
$reply = $this->send_cmd("PASS $pass");
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 pass: " . _("Authentication failed") . " [$reply]";
$this->quit();
return false;
} else {
// Auth successful.
$count = $this->last("count");
$this->COUNT = $count;
return $count;
}
}
}
function apop ($login,$pass) {
// Attempts an APOP login. If this fails, it'll
// try a standard login. YOUR SERVER MUST SUPPORT
// THE USE OF THE APOP COMMAND!
// (apop is optional per rfc1939)
if(!isset($this->FP)) {
$this->ERROR = "POP3 apop: " . _("No connection to server");
return false;
} elseif(!$this->ALLOWAPOP) {
$retVal = $this->login($login,$pass);
return $retVal;
} elseif(empty($login)) {
$this->ERROR = "POP3 apop: " . _("No login ID submitted");
return false;
} elseif(empty($pass)) {
$this->ERROR = "POP3 apop: " . _("No password submitted");
return false;
} else {
$banner = $this->BANNER;
if( (!$banner) or (empty($banner)) ) {
$this->ERROR = "POP3 apop: " . _("No server banner") . ' - ' . _("abort");
$retVal = $this->login($login,$pass);
return $retVal;
} else {
$AuthString = $banner;
$AuthString .= $pass;
$APOPString = md5($AuthString);
$cmd = "APOP $login $APOPString";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply)) {
$this->ERROR = "POP3 apop: " . _("apop authentication failed") . ' - ' . _("abort");
$retVal = $this->login($login,$pass);
return $retVal;
} else {
// Auth successful.
$count = $this->last("count");
$this->COUNT = $count;
return $count;
}
}
}
}
function login ($login = "", $pass = "") {
// Sends both user and pass. Returns # of msgs in mailbox or
// false on failure (or -1, if the error occurs while getting
// the number of messages.)
if( !isset($this->FP) ) {
$this->ERROR = "POP3 login: " . _("No connection to server");
return false;
} else {
$fp = $this->FP;
if( !$this->user( $login ) ) {
// Preserve the error generated by user()
return false;
} else {
$count = $this->pass($pass);
if( (!$count) || ($count == -1) ) {
// Preserve the error generated by last() and pass()
return false;
} else
return $count;
}
}
}
function top ($msgNum, $numLines = "0") {
// Gets the header and first $numLines of the msg body
// returns data in an array with each returned line being
// an array element. If $numLines is empty, returns
// only the header information, and none of the body.
if(!isset($this->FP)) {
$this->ERROR = "POP3 top: " . _("No connection to server");
return false;
}
$this->update_timer();
$fp = $this->FP;
$buffer = $this->BUFFER;
$cmd = "TOP $msgNum $numLines";
fwrite($fp, "TOP $msgNum $numLines\r\n");
$reply = fgets($fp, $buffer);
$reply = $this->strip_clf($reply);
if($this->DEBUG) {
@error_log("POP3 SEND [$cmd] GOT [$reply]",0);
}
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 top: " . _("Error ") . "[$reply]";
return false;
}
$count = 0;
$MsgArray = array();
$line = fgets($fp,$buffer);
while ( !preg_match('/^\.\r\n/',$line))
{
$MsgArray[$count] = $line;
$count++;
$line = fgets($fp,$buffer);
if(empty($line)) { break; }
}
return $MsgArray;
}
function pop_list ($msgNum = "") {
// If called with an argument, returns that msgs' size in octets
// No argument returns an associative array of undeleted
// msg numbers and their sizes in octets
if(!isset($this->FP))
{
$this->ERROR = "POP3 pop_list: " . _("No connection to server");
return false;
}
$fp = $this->FP;
$Total = $this->COUNT;
if( (!$Total) or ($Total == -1) )
{
return false;
}
if($Total == 0)
{
return array("0","0");
// return -1; // mailbox empty
}
$this->update_timer();
if(!empty($msgNum))
{
$cmd = "LIST $msgNum";
fwrite($fp,"$cmd\r\n");
$reply = fgets($fp,$this->BUFFER);
$reply = $this->strip_clf($reply);
if($this->DEBUG) {
@error_log("POP3 SEND [$cmd] GOT [$reply]",0);
}
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
return false;
}
list($junk,$num,$size) = preg_split('/\s+/',$reply);
return $size;
}
$cmd = "LIST";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply))
{
$reply = $this->strip_clf($reply);
$this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
return false;
}
$MsgArray = array();
$MsgArray[0] = $Total;
for($msgC=1;$msgC <= $Total; $msgC++)
{
if($msgC > $Total) { break; }
$line = fgets($fp,$this->BUFFER);
$line = $this->strip_clf($line);
if(strpos($line, '.') === 0)
{
$this->ERROR = "POP3 pop_list: " . _("Premature end of list");
return false;
}
list($thisMsg,$msgSize) = preg_split('/\s+/',$line);
settype($thisMsg,"integer");
if($thisMsg != $msgC)
{
$MsgArray[$msgC] = "deleted";
}
else
{
$MsgArray[$msgC] = $msgSize;
}
}
return $MsgArray;
}
function get ($msgNum) {
// Retrieve the specified msg number. Returns an array
// where each line of the msg is an array element.
if(!isset($this->FP))
{
$this->ERROR = "POP3 get: " . _("No connection to server");
return false;
}
$this->update_timer();
$fp = $this->FP;
$buffer = $this->BUFFER;
$cmd = "RETR $msgNum";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 get: " . _("Error ") . "[$reply]";
return false;
}
$count = 0;
$MsgArray = array();
$line = fgets($fp,$buffer);
while ( !preg_match('/^\.\r\n/',$line))
{
if ( $line[0] == '.' ) { $line = substr($line,1); }
$MsgArray[$count] = $line;
$count++;
$line = fgets($fp,$buffer);
if(empty($line)) { break; }
}
return $MsgArray;
}
function last ( $type = "count" ) {
// Returns the highest msg number in the mailbox.
// returns -1 on error, 0+ on success, if type != count
// results in a popstat() call (2 element array returned)
$last = -1;
if(!isset($this->FP))
{
$this->ERROR = "POP3 last: " . _("No connection to server");
return $last;
}
$reply = $this->send_cmd("STAT");
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 last: " . _("Error ") . "[$reply]";
return $last;
}
$Vars = preg_split('/\s+/',$reply);
$count = $Vars[1];
$size = $Vars[2];
settype($count,"integer");
settype($size,"integer");
if($type != "count")
{
return array($count,$size);
}
return $count;
}
function reset () {
// Resets the status of the remote server. This includes
// resetting the status of ALL msgs to not be deleted.
// This method automatically closes the connection to the server.
if(!isset($this->FP))
{
$this->ERROR = "POP3 reset: " . _("No connection to server");
return false;
}
$reply = $this->send_cmd("RSET");
if(!$this->is_ok($reply))
{
// The POP3 RSET command -never- gives a -ERR
// response - if it ever does, something truly
// wild is going on.
$this->ERROR = "POP3 reset: " . _("Error ") . "[$reply]";
@error_log("POP3 reset: ERROR [$reply]",0);
}
$this->quit();
return true;
}
function send_cmd ( $cmd = "" )
{
// Sends a user defined command string to the
// POP server and returns the results. Useful for
// non-compliant or custom POP servers.
// Do NOT include the \r\n as part of your command
// string - it will be appended automatically.
// The return value is a standard fgets() call, which
// will read up to $this->BUFFER bytes of data, until it
// encounters a new line, or EOF, whichever happens first.
// This method works best if $cmd responds with only
// one line of data.
if(!isset($this->FP))
{
$this->ERROR = "POP3 send_cmd: " . _("No connection to server");
return false;
}
if(empty($cmd))
{
$this->ERROR = "POP3 send_cmd: " . _("Empty command string");
return "";
}
$fp = $this->FP;
$buffer = $this->BUFFER;
$this->update_timer();
fwrite($fp,"$cmd\r\n");
$reply = fgets($fp,$buffer);
$reply = $this->strip_clf($reply);
if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
return $reply;
}
function quit() {
// Closes the connection to the POP3 server, deleting
// any msgs marked as deleted.
if(!isset($this->FP))
{
$this->ERROR = "POP3 quit: " . _("connection does not exist");
return false;
}
$fp = $this->FP;
$cmd = "QUIT";
fwrite($fp,"$cmd\r\n");
$reply = fgets($fp,$this->BUFFER);
$reply = $this->strip_clf($reply);
if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
fclose($fp);
unset($this->FP);
return true;
}
function popstat () {
// Returns an array of 2 elements. The number of undeleted
// msgs in the mailbox, and the size of the mbox in octets.
$PopArray = $this->last("array");
if($PopArray == -1) { return false; }
if( (!$PopArray) or (empty($PopArray)) )
{
return false;
}
return $PopArray;
}
function uidl ($msgNum = "")
{
// Returns the UIDL of the msg specified. If called with
// no arguments, returns an associative array where each
// undeleted msg num is a key, and the msg's uidl is the element
// Array element 0 will contain the total number of msgs
if(!isset($this->FP)) {
$this->ERROR = "POP3 uidl: " . _("No connection to server");
return false;
}
$fp = $this->FP;
$buffer = $this->BUFFER;
if(!empty($msgNum)) {
$cmd = "UIDL $msgNum";
$reply = $this->send_cmd($cmd);
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
return false;
}
list ($ok,$num,$myUidl) = preg_split('/\s+/',$reply);
return $myUidl;
} else {
$this->update_timer();
$UIDLArray = array();
$Total = $this->COUNT;
$UIDLArray[0] = $Total;
if ($Total < 1)
{
return $UIDLArray;
}
$cmd = "UIDL";
fwrite($fp, "UIDL\r\n");
$reply = fgets($fp, $buffer);
$reply = $this->strip_clf($reply);
if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
return false;
}
$line = "";
$count = 1;
$line = fgets($fp,$buffer);
while ( !preg_match('/^\.\r\n/',$line)) {
list ($msg,$msgUidl) = preg_split('/\s+/',$line);
$msgUidl = $this->strip_clf($msgUidl);
if($count == $msg) {
$UIDLArray[$msg] = $msgUidl;
}
else
{
$UIDLArray[$count] = 'deleted';
}
$count++;
$line = fgets($fp,$buffer);
}
}
return $UIDLArray;
}
function delete ($msgNum = "") {
// Flags a specified msg as deleted. The msg will not
// be deleted until a quit() method is called.
if(!isset($this->FP))
{
$this->ERROR = "POP3 delete: " . _("No connection to server");
return false;
}
if(empty($msgNum))
{
$this->ERROR = "POP3 delete: " . _("No msg number submitted");
return false;
}
$reply = $this->send_cmd("DELE $msgNum");
if(!$this->is_ok($reply))
{
$this->ERROR = "POP3 delete: " . _("Command failed ") . "[$reply]";
return false;
}
return true;
}
// *********************************************************
// The following methods are internal to the class.
function is_ok ($cmd = "") {
// Return true or false on +OK or -ERR
if( empty($cmd) )
return false;
else
return( stripos($cmd, '+OK') !== false );
}
function strip_clf ($text = "") {
// Strips \r\n from server responses
if(empty($text))
return $text;
else {
$stripped = str_replace(array("\r","\n"),'',$text);
return $stripped;
}
}
function parse_banner ( $server_text ) {
$outside = true;
$banner = "";
$length = strlen($server_text);
for($count =0; $count < $length; $count++)
{
$digit = substr($server_text,$count,1);
if(!empty($digit)) {
if( (!$outside) && ($digit != '<') && ($digit != '>') )
{
$banner .= $digit;
}
if ($digit == '<')
{
$outside = false;
}
if($digit == '>')
{
$outside = true;
}
}
}
$banner = $this->strip_clf($banner); // Just in case
return "<$banner>";
}
} // End class
// For php4 compatibility
if (!function_exists("stripos")) {
function stripos($haystack, $needle){
return strpos($haystack, stristr( $haystack, $needle ));
}
}
<?php
/**
* Dependencies API: WP_Styles class
*
* @since 2.6.0
*
* @package WordPress
* @subpackage Dependencies
*/
/**
* Core class used to register styles.
*
* @since 2.6.0
*
* @see WP_Dependencies
*/
class WP_Styles extends WP_Dependencies {
/**
* Base URL for styles.
*
* Full URL with trailing slash.
*
* @since 2.6.0
* @var string
*/
public $base_url;
/**
* URL of the content directory.
*
* @since 2.8.0
* @var string
*/
public $content_url;
/**
* Default version string for stylesheets.
*
* @since 2.6.0
* @var string
*/
public $default_version;
/**
* The current text direction.
*
* @since 2.6.0
* @var string
*/
public $text_direction = 'ltr';
/**
* Holds a list of style handles which will be concatenated.
*
* @since 2.8.0
* @var string
*/
public $concat = '';
/**
* Holds a string which contains style handles and their version.
*
* @since 2.8.0
* @deprecated 3.4.0
* @var string
*/
public $concat_version = '';
/**
* Whether to perform concatenation.
*
* @since 2.8.0
* @var bool
*/
public $do_concat = false;
/**
* Holds HTML markup of styles and additional data if concatenation
* is enabled.
*
* @since 2.8.0
* @var string
*/
public $print_html = '';
/**
* Holds inline styles if concatenation is enabled.
*
* @since 3.3.0
* @var string
*/
public $print_code = '';
/**
* List of default directories.
*
* @since 2.8.0
* @var array
*/
public $default_dirs;
/**
* Holds a string which contains the type attribute for style tag.
*
* If the active theme does not declare HTML5 support for 'style',
* then it initializes as `type='text/css'`.
*
* @since 5.3.0
* @var string
*/
private $type_attr = '';
/**
* Constructor.
*
* @since 2.6.0
*/
public function __construct() {
if (
function_exists( 'is_admin' ) && ! is_admin()
&&
function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' )
) {
$this->type_attr = " type='text/css'";
}
/**
* Fires when the WP_Styles instance is initialized.
*
* @since 2.6.0
*
* @param WP_Styles $wp_styles WP_Styles instance (passed by reference).
*/
do_action_ref_array( 'wp_default_styles', array( &$this ) );
}
/**
* Processes a style dependency.
*
* @since 2.6.0
* @since 5.5.0 Added the `$group` parameter.
*
* @see WP_Dependencies::do_item()
*
* @param string $handle The style's registered handle.
* @param int|false $group Optional. Group level: level (int), no groups (false).
* Default false.
* @return bool True on success, false on failure.
*/
public function do_item( $handle, $group = false ) {
if ( ! parent::do_item( $handle ) ) {
return false;
}
$obj = $this->registered[ $handle ];
if ( null === $obj->ver ) {
$ver = '';
} else {
$ver = $obj->ver ? $obj->ver : $this->default_version;
}
if ( isset( $this->args[ $handle ] ) ) {
$ver = $ver ? $ver . '&' . $this->args[ $handle ] : $this->args[ $handle ];
}
$src = $obj->src;
$ie_conditional_prefix = '';
$ie_conditional_suffix = '';
$conditional = isset( $obj->extra['conditional'] ) ? $obj->extra['conditional'] : '';
if ( $conditional ) {
$ie_conditional_prefix = "<!--[if {$conditional}]>\n";
$ie_conditional_suffix = "<![endif]-->\n";
}
$inline_style = $this->print_inline_style( $handle, false );
if ( $inline_style ) {
$inline_style_tag = sprintf(
"<style id='%s-inline-css'%s>\n%s\n</style>\n",
esc_attr( $handle ),
$this->type_attr,
$inline_style
);
} else {
$inline_style_tag = '';
}
if ( $this->do_concat ) {
if ( $this->in_default_dir( $src ) && ! $conditional && ! isset( $obj->extra['alt'] ) ) {
$this->concat .= "$handle,";
$this->concat_version .= "$handle$ver";
$this->print_code .= $inline_style;
return true;
}
}
if ( isset( $obj->args ) ) {
$media = esc_attr( $obj->args );
} else {
$media = 'all';
}
// A single item may alias a set of items, by having dependencies, but no source.
if ( ! $src ) {
if ( $inline_style_tag ) {
if ( $this->do_concat ) {
$this->print_html .= $inline_style_tag;
} else {
echo $inline_style_tag;
}
}
return true;
}
$href = $this->_css_href( $src, $ver, $handle );
if ( ! $href ) {
return true;
}
$rel = isset( $obj->extra['alt'] ) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
$title = isset( $obj->extra['title'] ) ? sprintf( " title='%s'", esc_attr( $obj->extra['title'] ) ) : '';
$tag = sprintf(
"<link rel='%s' id='%s-css'%s href='%s'%s media='%s' />\n",
$rel,
$handle,
$title,
$href,
$this->type_attr,
$media
);
/**
* Filters the HTML link tag of an enqueued style.
*
* @since 2.6.0
* @since 4.3.0 Introduced the `$href` parameter.
* @since 4.5.0 Introduced the `$media` parameter.
*
* @param string $tag The link tag for the enqueued style.
* @param string $handle The style's registered handle.
* @param string $href The stylesheet's source URL.
* @param string $media The stylesheet's media attribute.
*/
$tag = apply_filters( 'style_loader_tag', $tag, $handle, $href, $media );
if ( 'rtl' === $this->text_direction && isset( $obj->extra['rtl'] ) && $obj->extra['rtl'] ) {
if ( is_bool( $obj->extra['rtl'] ) || 'replace' === $obj->extra['rtl'] ) {
$suffix = isset( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
$rtl_href = str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $this->_css_href( $src, $ver, "$handle-rtl" ) );
} else {
$rtl_href = $this->_css_href( $obj->extra['rtl'], $ver, "$handle-rtl" );
}
$rtl_tag = sprintf(
"<link rel='%s' id='%s-rtl-css'%s href='%s'%s media='%s' />\n",
$rel,
$handle,
$title,
$rtl_href,
$this->type_attr,
$media
);
/** This filter is documented in wp-includes/class-wp-styles.php */
$rtl_tag = apply_filters( 'style_loader_tag', $rtl_tag, $handle, $rtl_href, $media );
if ( 'replace' === $obj->extra['rtl'] ) {
$tag = $rtl_tag;
} else {
$tag .= $rtl_tag;
}
}
if ( $this->do_concat ) {
$this->print_html .= $ie_conditional_prefix;
$this->print_html .= $tag;
if ( $inline_style_tag ) {
$this->print_html .= $inline_style_tag;
}
$this->print_html .= $ie_conditional_suffix;
} else {
echo $ie_conditional_prefix;
echo $tag;
$this->print_inline_style( $handle );
echo $ie_conditional_suffix;
}
return true;
}
/**
* Adds extra CSS styles to a registered stylesheet.
*
* @since 3.3.0
*
* @param string $handle The style's registered handle.
* @param string $code String containing the CSS styles to be added.
* @return bool True on success, false on failure.
*/
public function add_inline_style( $handle, $code ) {
if ( ! $code ) {
return false;
}
$after = $this->get_data( $handle, 'after' );
if ( ! $after ) {
$after = array();
}
$after[] = $code;
return $this->add_data( $handle, 'after', $after );
}
/**
* Prints extra CSS styles of a registered stylesheet.
*
* @since 3.3.0
*
* @param string $handle The style's registered handle.
* @param bool $display Optional. Whether to print the inline style
* instead of just returning it. Default true.
* @return string|bool False if no data exists, inline styles if `$display` is true,
* true otherwise.
*/
public function print_inline_style( $handle, $display = true ) {
$output = $this->get_data( $handle, 'after' );
if ( empty( $output ) ) {
return false;
}
$output = implode( "\n", $output );
if ( ! $display ) {
return $output;
}
printf(
"<style id='%s-inline-css'%s>\n%s\n</style>\n",
esc_attr( $handle ),
$this->type_attr,
$output
);
return true;
}
/**
* Determines style dependencies.
*
* @since 2.6.0
*
* @see WP_Dependencies::all_deps()
*
* @param string|string[] $handles Item handle (string) or item handles (array of strings).
* @param bool $recursion Optional. Internal flag that function is calling itself.
* Default false.
* @param int|false $group Optional. Group level: level (int), no groups (false).
* Default false.
* @return bool True on success, false on failure.
*/
public function all_deps( $handles, $recursion = false, $group = false ) {
$result = parent::all_deps( $handles, $recursion, $group );
if ( ! $recursion ) {
/**
* Filters the array of enqueued styles before processing for output.
*
* @since 2.6.0
*
* @param string[] $to_do The list of enqueued style handles about to be processed.
*/
$this->to_do = apply_filters( 'print_styles_array', $this->to_do );
}
return $result;
}
/**
* Generates an enqueued style's fully-qualified URL.
*
* @since 2.6.0
*
* @param string $src The source of the enqueued style.
* @param string $ver The version of the enqueued style.
* @param string $handle The style's registered handle.
* @return string Style's fully-qualified URL.
*/
public function _css_href( $src, $ver, $handle ) {
if ( ! is_bool( $src ) && ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) {
$src = $this->base_url . $src;
}
if ( ! empty( $ver ) ) {
$src = add_query_arg( 'ver', $ver, $src );
}
/**
* Filters an enqueued style's fully-qualified URL.
*
* @since 2.6.0
*
* @param string $src The source URL of the enqueued style.
* @param string $handle The style's registered handle.
*/
$src = apply_filters( 'style_loader_src', $src, $handle );
return esc_url( $src );
}
/**
* Whether a handle's source is in a default directory.
*
* @since 2.8.0
*
* @param string $src The source of the enqueued style.
* @return bool True if found, false if not.
*/
public function in_default_dir( $src ) {
if ( ! $this->default_dirs ) {
return true;
}
foreach ( (array) $this->default_dirs as $test ) {
if ( str_starts_with( $src, $test ) ) {
return true;
}
}
return false;
}
/**
* Processes items and dependencies for the footer group.
*
* HTML 5 allows styles in the body, grab late enqueued items and output them in the footer.
*
* @since 3.3.0
*
* @see WP_Dependencies::do_items()
*
* @return string[] Handles of items that have been processed.
*/
public function do_footer_items() {
$this->do_items( false, 1 );
return $this->done;
}
/**
* Resets class properties.
*
* @since 3.3.0
*/
public function reset() {
$this->do_concat = false;
$this->concat = '';
$this->concat_version = '';
$this->print_html = '';
}
}
<?php
/**
* Block template loader functions.
*
* @package WordPress
*/
/**
* Adds necessary hooks to resolve '_wp-find-template' requests.
*
* @access private
* @since 5.9.0
*/
function _add_template_loader_filters() {
if ( isset( $_GET['_wp-find-template'] ) && current_theme_supports( 'block-templates' ) ) {
add_action( 'pre_get_posts', '_resolve_template_for_new_post' );
}
}
/**
* Renders a warning screen for empty block templates.
*
* @since 6.8.0
*
* @param WP_Block_Template $block_template The block template object.
* @return string The warning screen HTML.
*/
function wp_render_empty_block_template_warning( $block_template ) {
wp_enqueue_style( 'wp-empty-template-alert' );
return sprintf(
/* translators: %1$s: Block template title. %2$s: Empty template warning message. %3$s: Edit template link. %4$s: Edit template button label. */
'<div id="wp-empty-template-alert">
<h2>%1$s</h2>
<p>%2$s</p>
<a href="%3$s" class="wp-element-button">
%4$s
</a>
</div>',
esc_html( $block_template->title ),
__( 'This page is blank because the template is empty. You can reset or customize it in the Site Editor.' ),
get_edit_post_link( $block_template->wp_id, 'site-editor' ),
__( 'Edit template' )
);
}
/**
* Finds a block template with equal or higher specificity than a given PHP template file.
*
* Internally, this communicates the block content that needs to be used by the template canvas through a global variable.
*
* @since 5.8.0
* @since 6.3.0 Added `$_wp_current_template_id` global for editing of current template directly from the admin bar.
*
* @global string $_wp_current_template_content
* @global string $_wp_current_template_id
*
* @param string $template Path to the template. See locate_template().
* @param string $type Sanitized filename without extension.
* @param string[] $templates A list of template candidates, in descending order of priority.
* @return string The path to the Site Editor template canvas file, or the fallback PHP template.
*/
function locate_block_template( $template, $type, array $templates ) {
global $_wp_current_template_content, $_wp_current_template_id;
if ( ! current_theme_supports( 'block-templates' ) ) {
return $template;
}
if ( $template ) {
/*
* locate_template() has found a PHP template at the path specified by $template.
* That means that we have a fallback candidate if we cannot find a block template
* with higher specificity.
*
* Thus, before looking for matching block themes, we shorten our list of candidate
* templates accordingly.
*/
// Locate the index of $template (without the theme directory path) in $templates.
$relative_template_path = str_replace(
array( get_stylesheet_directory() . '/', get_template_directory() . '/' ),
'',
$template
);
$index = array_search( $relative_template_path, $templates, true );
// If the template hierarchy algorithm has successfully located a PHP template file,
// we will only consider block templates with higher or equal specificity.
$templates = array_slice( $templates, 0, $index + 1 );
}
$block_template = resolve_block_template( $type, $templates, $template );
if ( $block_template ) {
$_wp_current_template_id = $block_template->id;
if ( empty( $block_template->content ) ) {
if ( is_user_logged_in() ) {
$_wp_current_template_content = wp_render_empty_block_template_warning( $block_template );
} else {
if ( $block_template->has_theme_file ) {
// Show contents from theme template if user is not logged in.
$theme_template = _get_block_template_file( 'wp_template', $block_template->slug );
$_wp_current_template_content = file_get_contents( $theme_template['path'] );
} else {
$_wp_current_template_content = $block_template->content;
}
}
} elseif ( ! empty( $block_template->content ) ) {
$_wp_current_template_content = $block_template->content;
}
if ( isset( $_GET['_wp-find-template'] ) ) {
wp_send_json_success( $block_template );
}
} else {
if ( $template ) {
return $template;
}
if ( 'index' === $type ) {
if ( isset( $_GET['_wp-find-template'] ) ) {
wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) );
}
} else {
return ''; // So that the template loader keeps looking for templates.
}
}
// Add hooks for template canvas.
// Add viewport meta tag.
add_action( 'wp_head', '_block_template_viewport_meta_tag', 0 );
// Render title tag with content, regardless of whether theme has title-tag support.
remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering...
add_action( 'wp_head', '_block_template_render_title_tag', 1 ); // ...and make it unconditional.
// This file will be included instead of the theme's template file.
return ABSPATH . WPINC . '/template-canvas.php';
}
/**
* Returns the correct 'wp_template' to render for the request template type.
*
* @access private
* @since 5.8.0
* @since 5.9.0 Added the `$fallback_template` parameter.
*
* @param string $template_type The current template type.
* @param string[] $template_hierarchy The current template hierarchy, ordered by priority.
* @param string $fallback_template A PHP fallback template to use if no matching block template is found.
* @return WP_Block_Template|null template A template object, or null if none could be found.
*/
function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) {
if ( ! $template_type ) {
return null;
}
if ( empty( $template_hierarchy ) ) {
$template_hierarchy = array( $template_type );
}
$slugs = array_map(
'_strip_template_file_suffix',
$template_hierarchy
);
// Find all potential templates 'wp_template' post matching the hierarchy.
$query = array(
'slug__in' => $slugs,
);
$templates = get_block_templates( $query );
// Order these templates per slug priority.
// Build map of template slugs to their priority in the current hierarchy.
$slug_priorities = array_flip( $slugs );
usort(
$templates,
static function ( $template_a, $template_b ) use ( $slug_priorities ) {
return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ];
}
);
$theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR;
$parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR;
// Is the active theme a child theme, and is the PHP fallback template part of it?
if (
str_starts_with( $fallback_template, $theme_base_path ) &&
! str_contains( $fallback_template, $parent_theme_base_path )
) {
$fallback_template_slug = substr(
$fallback_template,
// Starting position of slug.
strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ),
// Remove '.php' suffix.
-4
);
// Is our candidate block template's slug identical to our PHP fallback template's?
if (
count( $templates ) &&
$fallback_template_slug === $templates[0]->slug &&
'theme' === $templates[0]->source
) {
// Unfortunately, we cannot trust $templates[0]->theme, since it will always
// be set to the active theme's slug by _build_block_template_result_from_file(),
// even if the block template is really coming from the active theme's parent.
// (The reason for this is that we want it to be associated with the active theme
// -- not its parent -- once we edit it and store it to the DB as a wp_template CPT.)
// Instead, we use _get_block_template_file() to locate the block template file.
$template_file = _get_block_template_file( 'wp_template', $fallback_template_slug );
if ( $template_file && get_template() === $template_file['theme'] ) {
// The block template is part of the parent theme, so we
// have to give precedence to the child theme's PHP template.
array_shift( $templates );
}
}
}
return count( $templates ) ? $templates[0] : null;
}
/**
* Displays title tag with content, regardless of whether theme has title-tag support.
*
* @access private
* @since 5.8.0
*
* @see _wp_render_title_tag()
*/
function _block_template_render_title_tag() {
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}
/**
* Returns the markup for the current template.
*
* @access private
* @since 5.8.0
*
* @global string $_wp_current_template_id
* @global string $_wp_current_template_content
* @global WP_Embed $wp_embed WordPress Embed object.
* @global WP_Query $wp_query WordPress Query object.
*
* @return string Block template markup.
*/
function get_the_block_template_html() {
global $_wp_current_template_id, $_wp_current_template_content, $wp_embed, $wp_query;
if ( ! $_wp_current_template_content ) {
if ( is_user_logged_in() ) {
return '<h1>' . esc_html__( 'No matching template found' ) . '</h1>';
}
return;
}
$content = $wp_embed->run_shortcode( $_wp_current_template_content );
$content = $wp_embed->autoembed( $content );
$content = shortcode_unautop( $content );
$content = do_shortcode( $content );
/*
* Most block themes omit the `core/query` and `core/post-template` blocks in their singular content templates.
* While this technically still works since singular content templates are always for only one post, it results in
* the main query loop never being entered which causes bugs in core and the plugin ecosystem.
*
* The workaround below ensures that the loop is started even for those singular templates. The while loop will by
* definition only go through a single iteration, i.e. `do_blocks()` is only called once. Additional safeguard
* checks are included to ensure the main query loop has not been tampered with and really only encompasses a
* single post.
*
* Even if the block template contained a `core/query` and `core/post-template` block referencing the main query
* loop, it would not cause errors since it would use a cloned instance and go through the same loop of a single
* post, within the actual main query loop.
*
* This special logic should be skipped if the current template does not come from the current theme, in which case
* it has been injected by a plugin by hijacking the block template loader mechanism. In that case, entirely custom
* logic may be applied which is unpredictable and therefore safer to omit this special handling on.
*/
if (
$_wp_current_template_id &&
str_starts_with( $_wp_current_template_id, get_stylesheet() . '//' ) &&
is_singular() &&
1 === $wp_query->post_count &&
have_posts()
) {
while ( have_posts() ) {
the_post();
$content = do_blocks( $content );
}
} else {
$content = do_blocks( $content );
}
$content = wptexturize( $content );
$content = convert_smilies( $content );
$content = wp_filter_content_tags( $content, 'template' );
$content = str_replace( ']]>', ']]>', $content );
// Wrap block template in .wp-site-blocks to allow for specific descendant styles
// (e.g. `.wp-site-blocks > *`).
return '<div class="wp-site-blocks">' . $content . '</div>';
}
/**
* Renders a 'viewport' meta tag.
*
* This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas.
*
* @access private
* @since 5.8.0
*/
function _block_template_viewport_meta_tag() {
echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n";
}
/**
* Strips .php or .html suffix from template file names.
*
* @access private
* @since 5.8.0
*
* @param string $template_file Template file name.
* @return string Template file name without extension.
*/
function _strip_template_file_suffix( $template_file ) {
return preg_replace( '/\.(php|html)$/', '', $template_file );
}
/**
* Removes post details from block context when rendering a block template.
*
* @access private
* @since 5.8.0
*
* @param array $context Default context.
*
* @return array Filtered context.
*/
function _block_template_render_without_post_block_context( $context ) {
/*
* When loading a template directly and not through a page that resolves it,
* the top-level post ID and type context get set to that of the template.
* Templates are just the structure of a site, and they should not be available
* as post context because blocks like Post Content would recurse infinitely.
*/
if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) {
unset( $context['postId'] );
unset( $context['postType'] );
}
return $context;
}
/**
* Sets the current WP_Query to return auto-draft posts.
*
* The auto-draft status indicates a new post, so allow the the WP_Query instance to
* return an auto-draft post for template resolution when editing a new post.
*
* @access private
* @since 5.9.0
*
* @param WP_Query $wp_query Current WP_Query instance, passed by reference.
*/
function _resolve_template_for_new_post( $wp_query ) {
if ( ! $wp_query->is_main_query() ) {
return;
}
remove_filter( 'pre_get_posts', '_resolve_template_for_new_post' );
// Pages.
$page_id = isset( $wp_query->query['page_id'] ) ? $wp_query->query['page_id'] : null;
// Posts, including custom post types.
$p = isset( $wp_query->query['p'] ) ? $wp_query->query['p'] : null;
$post_id = $page_id ? $page_id : $p;
$post = get_post( $post_id );
if (
$post &&
'auto-draft' === $post->post_status &&
current_user_can( 'edit_post', $post->ID )
) {
$wp_query->set( 'post_status', 'auto-draft' );
}
}
/**
* Register a block template.
*
* @since 6.7.0
*
* @param string $template_name Template name in the form of `plugin_uri//template_name`.
* @param array|string $args {
* @type string $title Optional. Title of the template as it will be shown in the Site Editor
* and other UI elements.
* @type string $description Optional. Description of the template as it will be shown in the Site
* Editor.
* @type string $content Optional. Default content of the template that will be used when the
* template is rendered or edited in the editor.
* @type string[] $post_types Optional. Array of post types to which the template should be available.
* @type string $plugin Optional. Slug of the plugin that registers the template.
* }
* @return WP_Block_Template|WP_Error The registered template object on success, WP_Error object on failure.
*/
function register_block_template( $template_name, $args = array() ) {
return WP_Block_Templates_Registry::get_instance()->register( $template_name, $args );
}
/**
* Unregister a block template.
*
* @since 6.7.0
*
* @param string $template_name Template name in the form of `plugin_uri//template_name`.
* @return WP_Block_Template|WP_Error The unregistered template object on success, WP_Error object on failure or if the
* template doesn't exist.
*/
function unregister_block_template( $template_name ) {
return WP_Block_Templates_Registry::get_instance()->unregister( $template_name );
}
<?php return array('a11y.min.js' => array('dependencies' => array('wp-dom-ready', 'wp-i18n'), 'version' => '3156534cc54473497e14'), 'annotations.min.js' => array('dependencies' => array('wp-data', 'wp-hooks', 'wp-i18n', 'wp-rich-text'), 'version' => '238360e96c76d37a2468'), 'api-fetch.min.js' => array('dependencies' => array('wp-i18n', 'wp-url'), 'version' => '3623a576c78df404ff20'), 'autop.min.js' => array('dependencies' => array(), 'version' => '9fb50649848277dd318d'), 'blob.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '9113eed771d446f4a556'), 'block-directory.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-primitives', 'wp-url'), 'version' => '5cecf7d562a5ae133696'), 'block-editor.min.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-priority-queue', 'wp-private-apis', 'wp-rich-text', 'wp-style-engine', 'wp-token-list', 'wp-url', 'wp-warning'), 'version' => 'c8c5e4e00ad4a1c77679'), 'block-library.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-autop', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-patterns', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-wordcount'), 'version' => 'da3dad2e2f76224eccfe'), 'block-serialization-default-parser.min.js' => array('dependencies' => array(), 'version' => '14d44daebf663d05d330'), 'blocks.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-autop', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-private-apis', 'wp-rich-text', 'wp-shortcode', 'wp-warning'), 'version' => '84530c06a3c62815b497'), 'commands.min.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-primitives', 'wp-private-apis'), 'version' => '14ee29ad1743be844b11'), 'components.min.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-compose', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-warning'), 'version' => '336a01176fa8097fbf37'), 'compose.min.js' => array('dependencies' => array('react', 'react-jsx-runtime', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-priority-queue'), 'version' => '84bcf832a5c99203f3db'), 'core-commands.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-commands', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-router', 'wp-url'), 'version' => 'afcb83dba96ea45361e9'), 'core-data.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-private-apis', 'wp-rich-text', 'wp-url', 'wp-warning'), 'version' => '64479bc080c558e99158'), 'customize-widgets.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-widgets'), 'version' => '42a5462097681fd98f6f'), 'data.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-deprecated', 'wp-element', 'wp-is-shallow-equal', 'wp-priority-queue', 'wp-private-apis', 'wp-redux-routine'), 'version' => 'fe6c4835cd00e12493c3'), 'data-controls.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-data', 'wp-deprecated'), 'version' => '49f5587e8b90f9e7cc7e'), 'date.min.js' => array('dependencies' => array('moment', 'wp-deprecated'), 'version' => '85ff222add187a4e358f'), 'deprecated.min.js' => array('dependencies' => array('wp-hooks'), 'version' => 'e1f84915c5e8ae38964c'), 'dom.min.js' => array('dependencies' => array('wp-deprecated'), 'version' => 'f3a673a30f968c8fa314'), 'dom-ready.min.js' => array('dependencies' => array(), 'version' => 'f77871ff7694fffea381'), 'edit-post.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-widgets'), 'version' => 'd92354a82041cfd9f542'), 'edit-site.min.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-router', 'wp-url', 'wp-warning', 'wp-widgets'), 'version' => '4cfd4c6e8c033bb1b61a'), 'edit-widgets.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-viewport', 'wp-widgets'), 'version' => '9a04bb29c0759b535e9e'), 'editor.min.js' => array('dependencies' => array('react', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-viewport', 'wp-warning', 'wp-wordcount'), 'version' => 'e143f7bc0f4773342f31'), 'element.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-escape-html'), 'version' => 'a4eeeadd23c0d7ab1d2d'), 'escape-html.min.js' => array('dependencies' => array(), 'version' => '6561a406d2d232a6fbd2'), 'format-library.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-url'), 'version' => 'f813b03986e369dad65e'), 'hooks.min.js' => array('dependencies' => array(), 'version' => '4d63a3d491d11ffd8ac6'), 'html-entities.min.js' => array('dependencies' => array(), 'version' => '2cd3358363e0675638fb'), 'i18n.min.js' => array('dependencies' => array('wp-hooks'), 'version' => '5e580eb46a90c2b997e6'), 'is-shallow-equal.min.js' => array('dependencies' => array(), 'version' => 'e0f9f1d78d83f5196979'), 'keyboard-shortcuts.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-data', 'wp-element', 'wp-keycodes'), 'version' => '32686e58e84193ce808b'), 'keycodes.min.js' => array('dependencies' => array('wp-i18n'), 'version' => '034ff647a54b018581d3'), 'list-reusable-blocks.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-blob', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n'), 'version' => 'ece12b3c74315b4175ef'), 'media-utils.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-blob', 'wp-element', 'wp-i18n', 'wp-private-apis'), 'version' => 'c3dd622ad8417c2d4474'), 'notices.min.js' => array('dependencies' => array('wp-data'), 'version' => '673a68a7ac2f556ed50b'), 'nux.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '9a0dc535fe222ae46a48'), 'patterns.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => '6497476653868ae9d711'), 'plugins.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-deprecated', 'wp-element', 'wp-hooks', 'wp-is-shallow-equal', 'wp-primitives'), 'version' => '20303a2de19246c83e5a'), 'preferences.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-private-apis'), 'version' => '4aa23582b858c882a887'), 'preferences-persistence.min.js' => array('dependencies' => array('wp-api-fetch'), 'version' => '9307a8c9e3254140a223'), 'primitives.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-element'), 'version' => 'aef2543ab60c8c9bb609'), 'priority-queue.min.js' => array('dependencies' => array(), 'version' => '9c21c957c7e50ffdbf48'), 'private-apis.min.js' => array('dependencies' => array(), 'version' => '0f8478f1ba7e0eea562b'), 'redux-routine.min.js' => array('dependencies' => array(), 'version' => '8bb92d45458b29590f53'), 'reusable-blocks.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-url'), 'version' => '73735a77e4e5095733da'), 'rich-text.min.js' => array('dependencies' => array('wp-a11y', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-escape-html', 'wp-i18n', 'wp-keycodes'), 'version' => '74178fc8c4d67d66f1a8'), 'router.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-element', 'wp-polyfill', 'wp-private-apis', 'wp-url'), 'version' => 'e41607ae499191e0cb49'), 'server-side-render.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '345a014347e34be995f0'), 'shortcode.min.js' => array('dependencies' => array(), 'version' => 'b7747eee0efafd2f0c3b'), 'style-engine.min.js' => array('dependencies' => array(), 'version' => '08cc10e9532531e22456'), 'token-list.min.js' => array('dependencies' => array(), 'version' => '3b5f5dcfde830ecef24f'), 'url.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '6bf93e90403a1eec6501'), 'viewport.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-data'), 'version' => '829c9a30d366e1e5054c'), 'warning.min.js' => array('dependencies' => array(), 'version' => 'ed7c8b0940914f4fe44b'), 'widgets.min.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives'), 'version' => '0b561f75d41627a9d110'), 'wordcount.min.js' => array('dependencies' => array(), 'version' => '55d8c2bf3dc99e7ea5ec'));
<?php return array('dependencies' => array('wp-react-refresh-runtime'), 'version' => '461b2e321e6e009f2209');
<?php return array('interactivity/index.min.js' => array('dependencies' => array(), 'version' => '55aebb6e0a16726baffb', 'type' => 'module'), 'interactivity/debug.min.js' => array('dependencies' => array(), 'version' => 'a5c279b9ad67f2a4e6e2', 'type' => 'module'), 'interactivity-router/index.min.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/a11y', 'import' => 'dynamic')), 'version' => 'dc4a227f142d2e68ef83', 'type' => 'module'), 'a11y/index.min.js' => array('dependencies' => array(), 'version' => 'b7d06936b8bc23cff2ad', 'type' => 'module'), 'block-library/file/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'fdc2f6842e015af83140', 'type' => 'module'), 'block-library/form/view.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'baaf25398238b4f2a821', 'type' => 'module'), 'block-library/image/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'e38a2f910342023b9d19', 'type' => 'module'), 'block-library/navigation/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '61572d447d60c0aa5240', 'type' => 'module'), 'block-library/query/view.min.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/interactivity-router', 'import' => 'dynamic')), 'version' => 'f55e93a1ad4806e91785', 'type' => 'module'), 'block-library/search/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '208bf143e4074549fa89', 'type' => 'module'));
<?php return array('dependencies' => array(), 'version' => '8f1acdfb845f670b0ef2');
<?php return array('dependencies' => array(), 'version' => '8f1acdfb845f670b0ef2');
<?php return array('interactivity/index.js' => array('dependencies' => array(), 'version' => '48fc4752aca8f8795ca8', 'type' => 'module'), 'interactivity/debug.js' => array('dependencies' => array(), 'version' => 'beb31ebdbe898d3dd230', 'type' => 'module'), 'interactivity-router/index.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/a11y', 'import' => 'dynamic')), 'version' => '549bd2787122793df49c', 'type' => 'module'), 'a11y/index.js' => array('dependencies' => array(), 'version' => '2a5dd8e0f11b6868f8cf', 'type' => 'module'), 'block-library/file/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'e925ab60cccb6624004c', 'type' => 'module'), 'block-library/form/view.js' => array('dependencies' => array('wp-polyfill'), 'version' => '025c7429344421ccb2ef', 'type' => 'module'), 'block-library/image/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '23364a7b9437dd6c3319', 'type' => 'module'), 'block-library/navigation/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '0735c27ca16ce2f60efd', 'type' => 'module'), 'block-library/query/view.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/interactivity-router', 'import' => 'dynamic')), 'version' => '6ac3e743320307785d41', 'type' => 'module'), 'block-library/search/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'e7b1695e621770b7ebb8', 'type' => 'module'));
<?php return array('dependencies' => array('wp-react-refresh-runtime'), 'version' => '461b2e321e6e009f2209');
<?php return array('a11y.js' => array('dependencies' => array('wp-dom-ready', 'wp-i18n'), 'version' => '604a4359a838a9073d9f'), 'annotations.js' => array('dependencies' => array('wp-data', 'wp-hooks', 'wp-i18n', 'wp-rich-text'), 'version' => 'dfaab3186d5cfee4a4c2'), 'api-fetch.js' => array('dependencies' => array('wp-i18n', 'wp-url'), 'version' => '52446bd41c30bc419a05'), 'autop.js' => array('dependencies' => array(), 'version' => 'a0567e518e6863383ace'), 'blob.js' => array('dependencies' => array('wp-polyfill'), 'version' => '65d38acd0a443932b695'), 'block-directory.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-primitives', 'wp-url'), 'version' => '4663e7373a239c52d743'), 'block-editor.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-priority-queue', 'wp-private-apis', 'wp-rich-text', 'wp-style-engine', 'wp-token-list', 'wp-url', 'wp-warning'), 'version' => 'd5b81eb0e8bc8d678b05'), 'block-library.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-autop', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-patterns', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-wordcount'), 'version' => '4973f92abc0198544fdb'), 'block-serialization-default-parser.js' => array('dependencies' => array(), 'version' => '1d1bef54e84a98f3efb9'), 'blocks.js' => array('dependencies' => array('react-jsx-runtime', 'wp-autop', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-private-apis', 'wp-rich-text', 'wp-shortcode', 'wp-warning'), 'version' => 'e851ee8e9644a9abf7ed'), 'commands.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-primitives', 'wp-private-apis'), 'version' => 'afc09c8bf245fe46c7a0'), 'components.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-compose', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-warning'), 'version' => '0526106ae8fcc5b2e62d'), 'compose.js' => array('dependencies' => array('react', 'react-jsx-runtime', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-priority-queue'), 'version' => 'ccc1a46c6a7b3734d300'), 'core-commands.js' => array('dependencies' => array('react-jsx-runtime', 'wp-commands', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-router', 'wp-url'), 'version' => 'a0115e38272e1800dbd2'), 'core-data.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-private-apis', 'wp-rich-text', 'wp-url', 'wp-warning'), 'version' => '70ddde93f4f568925186'), 'customize-widgets.js' => array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-widgets'), 'version' => '96ce1edc9b683b77847c'), 'data.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-deprecated', 'wp-element', 'wp-is-shallow-equal', 'wp-priority-queue', 'wp-private-apis', 'wp-redux-routine'), 'version' => '2797f012cdb7d180a746'), 'data-controls.js' => array('dependencies' => array('wp-api-fetch', 'wp-data', 'wp-deprecated'), 'version' => 'e31cdcc73f3eea4fbe01'), 'date.js' => array('dependencies' => array('moment', 'wp-deprecated'), 'version' => '93f88d98de5601d8a46d'), 'deprecated.js' => array('dependencies' => array('wp-hooks'), 'version' => '741e32edb0e7c2dd30da'), 'dom.js' => array('dependencies' => array('wp-deprecated'), 'version' => '5c5821604f66f88e084b'), 'dom-ready.js' => array('dependencies' => array(), 'version' => '5b9fa8df0892dc9a7c41'), 'edit-post.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-widgets'), 'version' => 'dc6bbea5a448261ec8de'), 'edit-site.js' => array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-router', 'wp-url', 'wp-warning', 'wp-widgets'), 'version' => '2dd42f9ef237a6be1b5e'), 'edit-widgets.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-viewport', 'wp-widgets'), 'version' => '47b223cb88d85c713a6b'), 'editor.js' => array('dependencies' => array('react', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-viewport', 'wp-warning', 'wp-wordcount'), 'version' => '4faaac0109b050f1dbb2'), 'element.js' => array('dependencies' => array('react', 'react-dom', 'wp-escape-html'), 'version' => '6bd445740b34f5eae604'), 'escape-html.js' => array('dependencies' => array(), 'version' => '93558693d672af42c190'), 'format-library.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-url'), 'version' => '36151f5b565e0cdf6ddc'), 'hooks.js' => array('dependencies' => array(), 'version' => 'be67dc331e61e06d52fa'), 'html-entities.js' => array('dependencies' => array(), 'version' => '0d1913e5b8fb9137bad2'), 'i18n.js' => array('dependencies' => array('wp-hooks'), 'version' => '5edc734adb78e0d7d00e'), 'is-shallow-equal.js' => array('dependencies' => array(), 'version' => '58ed73f7376c883f832b'), 'keyboard-shortcuts.js' => array('dependencies' => array('react-jsx-runtime', 'wp-data', 'wp-element', 'wp-keycodes'), 'version' => 'c0e19c4aa8550cb4f71d'), 'keycodes.js' => array('dependencies' => array('wp-i18n'), 'version' => '2bad5660ad4ebde6540c'), 'list-reusable-blocks.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-blob', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n'), 'version' => 'ad48bd203f06c82d4c77'), 'media-utils.js' => array('dependencies' => array('wp-api-fetch', 'wp-blob', 'wp-element', 'wp-i18n', 'wp-private-apis'), 'version' => '6c862a9b6eee311930ac'), 'notices.js' => array('dependencies' => array('wp-data'), 'version' => 'bb7ea4346f0c7a77df98'), 'nux.js' => array('dependencies' => array('react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'a8290a113a755fbd665b'), 'patterns.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => 'ea1ca8506283289a8aeb'), 'plugins.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-deprecated', 'wp-element', 'wp-hooks', 'wp-is-shallow-equal', 'wp-primitives'), 'version' => '7313a68349c296697e15'), 'preferences.js' => array('dependencies' => array('react-jsx-runtime', 'wp-a11y', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-private-apis'), 'version' => 'f49ac7669ac11f416b6f'), 'preferences-persistence.js' => array('dependencies' => array('wp-api-fetch'), 'version' => 'a5baddbc610561581693'), 'primitives.js' => array('dependencies' => array('react-jsx-runtime', 'wp-element'), 'version' => '66632613c3c6b0ed6f76'), 'priority-queue.js' => array('dependencies' => array(), 'version' => 'be4e4334602693fa7256'), 'private-apis.js' => array('dependencies' => array(), 'version' => '18ea1d568a3bfd485afb'), 'redux-routine.js' => array('dependencies' => array(), 'version' => '9473249104d09cb1245d'), 'reusable-blocks.js' => array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-url'), 'version' => '03eefa7ca729412606a7'), 'rich-text.js' => array('dependencies' => array('wp-a11y', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-escape-html', 'wp-i18n', 'wp-keycodes'), 'version' => 'bc76e6f025d3556aa54a'), 'router.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-element', 'wp-polyfill', 'wp-private-apis', 'wp-url'), 'version' => '99ea3f320332583c3e5c'), 'server-side-render.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '5058284dc05b1b1b2661'), 'shortcode.js' => array('dependencies' => array(), 'version' => '37060a10de8dd991d95d'), 'style-engine.js' => array('dependencies' => array(), 'version' => '95bc9b8c9f4f0e8a6423'), 'token-list.js' => array('dependencies' => array(), 'version' => '09fdc83606f766278b8b'), 'url.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'de0b7a9192bc77a4d766'), 'viewport.js' => array('dependencies' => array('react-jsx-runtime', 'wp-compose', 'wp-data'), 'version' => '82036eb97185ee78762b'), 'warning.js' => array('dependencies' => array(), 'version' => '4ecd4ff4d8fa94314090'), 'widgets.js' => array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives'), 'version' => 'b2d3d6f0ca283bd27cbc'), 'wordcount.js' => array('dependencies' => array(), 'version' => 'f5354b03b95c624877fb'));
<?php
/**
* Feed API: WP_Feed_Cache_Transient class
*
* @package WordPress
* @subpackage Feed
* @since 4.7.0
*/
/**
* Core class used to implement feed cache transients.
*
* @since 2.8.0
* @since 6.7.0 Now properly implements the SimplePie\Cache\Base interface.
*/
#[AllowDynamicProperties]
class WP_Feed_Cache_Transient implements SimplePie\Cache\Base {
/**
* Holds the transient name.
*
* @since 2.8.0
* @var string
*/
public $name;
/**
* Holds the transient mod name.
*
* @since 2.8.0
* @var string
*/
public $mod_name;
/**
* Holds the cache duration in seconds.
*
* Defaults to 43200 seconds (12 hours).
*
* @since 2.8.0
* @var int
*/
public $lifetime = 43200;
/**
* Creates a new (transient) cache object.
*
* @since 2.8.0
* @since 3.2.0 Updated to use a PHP5 constructor.
* @since 6.7.0 Parameter names have been updated to be in line with the `SimplePie\Cache\Base` interface.
*
* @param string $location URL location (scheme is used to determine handler).
* @param string $name Unique identifier for cache object.
* @param Base::TYPE_FEED|Base::TYPE_IMAGE $type Either `TYPE_FEED` ('spc') for SimplePie data,
* or `TYPE_IMAGE` ('spi') for image data.
*/
public function __construct( $location, $name, $type ) {
$this->name = 'feed_' . $name;
$this->mod_name = 'feed_mod_' . $name;
$lifetime = $this->lifetime;
/**
* Filters the transient lifetime of the feed cache.
*
* @since 2.8.0
*
* @param int $lifetime Cache duration in seconds. Default is 43200 seconds (12 hours).
* @param string $name Unique identifier for the cache object.
*/
$this->lifetime = apply_filters( 'wp_feed_cache_transient_lifetime', $lifetime, $name );
}
/**
* Saves data to the transient.
*
* @since 2.8.0
*
* @param array|SimplePie\SimplePie $data Data to save. If passed a SimplePie object,
* only cache the `$data` property.
* @return true Always true.
*/
public function save( $data ) {
if ( $data instanceof SimplePie\SimplePie ) {
$data = $data->data;
}
set_transient( $this->name, $data, $this->lifetime );
set_transient( $this->mod_name, time(), $this->lifetime );
return true;
}
/**
* Retrieves the data saved in the transient.
*
* @since 2.8.0
*
* @return array Data for `SimplePie::$data`.
*/
public function load() {
return get_transient( $this->name );
}
/**
* Gets mod transient.
*
* @since 2.8.0
*
* @return int Timestamp.
*/
public function mtime() {
return get_transient( $this->mod_name );
}
/**
* Sets mod transient.
*
* @since 2.8.0
*
* @return bool False if value was not set and true if value was set.
*/
public function touch() {
return set_transient( $this->mod_name, time(), $this->lifetime );
}
/**
* Deletes transients.
*
* @since 2.8.0
*
* @return true Always true.
*/
public function unlink() {
delete_transient( $this->name );
delete_transient( $this->mod_name );
return true;
}
}
<?php
/**
* Class 'WP_URL_Pattern_Prefixer'.
*
* @package WordPress
* @subpackage Speculative Loading
* @since 6.8.0
*/
/**
* Class for prefixing URL patterns.
*
* This class is intended primarily for use as part of the speculative loading feature.
*
* @since 6.8.0
* @access private
*/
class WP_URL_Pattern_Prefixer {
/**
* Map of `$context_string => $base_path` pairs.
*
* @since 6.8.0
* @var array<string, string>
*/
private $contexts;
/**
* Constructor.
*
* @since 6.8.0
*
* @param array<string, string> $contexts Optional. Map of `$context_string => $base_path` pairs. Default is the
* contexts returned by the
* {@see WP_URL_Pattern_Prefixer::get_default_contexts()} method.
*/
public function __construct( array $contexts = array() ) {
if ( count( $contexts ) > 0 ) {
$this->contexts = array_map(
static function ( string $str ): string {
return self::escape_pattern_string( trailingslashit( $str ) );
},
$contexts
);
} else {
$this->contexts = self::get_default_contexts();
}
}
/**
* Prefixes the given URL path pattern with the base path for the given context.
*
* This ensures that these path patterns work correctly on WordPress subdirectory sites, for example in a multisite
* network, or when WordPress itself is installed in a subdirectory of the hostname.
*
* The given URL path pattern is only prefixed if it does not already include the expected prefix.
*
* @since 6.8.0
*
* @param string $path_pattern URL pattern starting with the path segment.
* @param string $context Optional. Context to use for prefixing the path pattern. Default 'home'.
* @return string URL pattern, prefixed as necessary.
*/
public function prefix_path_pattern( string $path_pattern, string $context = 'home' ): string {
// If context path does not exist, the context is invalid.
if ( ! isset( $this->contexts[ $context ] ) ) {
_doing_it_wrong(
__FUNCTION__,
esc_html(
sprintf(
/* translators: %s: context string */
__( 'Invalid URL pattern context %s.' ),
$context
)
),
'6.8.0'
);
return $path_pattern;
}
/*
* In the event that the context path contains a :, ? or # (which can cause the URL pattern parser to switch to
* another state, though only the latter two should be percent encoded anyway), it additionally needs to be
* enclosed in grouping braces. The final forward slash (trailingslashit ensures there is one) affects the
* meaning of the * wildcard, so is left outside the braces.
*/
$context_path = $this->contexts[ $context ];
$escaped_context_path = $context_path;
if ( strcspn( $context_path, ':?#' ) !== strlen( $context_path ) ) {
$escaped_context_path = '{' . substr( $context_path, 0, -1 ) . '}/';
}
/*
* If the path already starts with the context path (including '/'), remove it first
* since it is about to be added back.
*/
if ( str_starts_with( $path_pattern, $context_path ) ) {
$path_pattern = substr( $path_pattern, strlen( $context_path ) );
}
return $escaped_context_path . ltrim( $path_pattern, '/' );
}
/**
* Returns the default contexts used by the class.
*
* @since 6.8.0
*
* @return array<string, string> Map of `$context_string => $base_path` pairs.
*/
public static function get_default_contexts(): array {
return array(
'home' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( home_url( '/' ), PHP_URL_PATH ) ) ),
'site' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( site_url( '/' ), PHP_URL_PATH ) ) ),
'uploads' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( wp_upload_dir( null, false )['baseurl'], PHP_URL_PATH ) ) ),
'content' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( content_url(), PHP_URL_PATH ) ) ),
'plugins' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( plugins_url(), PHP_URL_PATH ) ) ),
'template' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( get_stylesheet_directory_uri(), PHP_URL_PATH ) ) ),
'stylesheet' => self::escape_pattern_string( trailingslashit( (string) wp_parse_url( get_template_directory_uri(), PHP_URL_PATH ) ) ),
);
}
/**
* Escapes a string for use in a URL pattern component.
*
* @since 6.8.0
* @see https://urlpattern.spec.whatwg.org/#escape-a-pattern-string
*
* @param string $str String to be escaped.
* @return string String with backslashes added where required.
*/
private static function escape_pattern_string( string $str ): string {
return addcslashes( $str, '+*?:{}()\\' );
}
}
<?php
/**
* WordPress Link Template Functions
*
* @package WordPress
* @subpackage Template
*/
/**
* Displays the permalink for the current post.
*
* @since 1.2.0
* @since 4.4.0 Added the `$post` parameter.
*
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
*/
function the_permalink( $post = 0 ) {
/**
* Filters the display of the permalink for the current post.
*
* @since 1.5.0
* @since 4.4.0 Added the `$post` parameter.
*
* @param string $permalink The permalink for the current post.
* @param int|WP_Post $post Post ID, WP_Post object, or 0. Default 0.
*/
echo esc_url( apply_filters( 'the_permalink', get_permalink( $post ), $post ) );
}
/**
* Retrieves a trailing-slashed string if the site is set for adding trailing slashes.
*
* Conditionally adds a trailing slash if the permalink structure has a trailing
* slash, strips the trailing slash if not. The string is passed through the
* {@see 'user_trailingslashit'} filter. Will remove trailing slash from string, if
* site is not set to have them.
*
* @since 2.2.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $url URL with or without a trailing slash.
* @param string $type_of_url Optional. The type of URL being considered (e.g. single, category, etc)
* for use in the filter. Default empty string.
* @return string The URL with the trailing slash appended or stripped.
*/
function user_trailingslashit( $url, $type_of_url = '' ) {
global $wp_rewrite;
if ( $wp_rewrite->use_trailing_slashes ) {
$url = trailingslashit( $url );
} else {
$url = untrailingslashit( $url );
}
/**
* Filters the trailing-slashed string, depending on whether the site is set to use trailing slashes.
*
* @since 2.2.0
*
* @param string $url URL with or without a trailing slash.
* @param string $type_of_url The type of URL being considered. Accepts 'single', 'single_trackback',
* 'single_feed', 'single_paged', 'commentpaged', 'paged', 'home', 'feed',
* 'category', 'page', 'year', 'month', 'day', 'post_type_archive'.
*/
return apply_filters( 'user_trailingslashit', $url, $type_of_url );
}
/**
* Displays the permalink anchor for the current post.
*
* The permalink mode title will use the post title for the 'a' element 'id'
* attribute. The id mode uses 'post-' with the post ID for the 'id' attribute.
*
* @since 0.71
*
* @param string $mode Optional. Permalink mode. Accepts 'title' or 'id'. Default 'id'.
*/
function permalink_anchor( $mode = 'id' ) {
$post = get_post();
switch ( strtolower( $mode ) ) {
case 'title':
$title = sanitize_title( $post->post_title ) . '-' . $post->ID;
echo '<a id="' . $title . '"></a>';
break;
case 'id':
default:
echo '<a id="post-' . $post->ID . '"></a>';
break;
}
}
/**
* Determine whether post should always use a plain permalink structure.
*
* @since 5.7.0
*
* @param WP_Post|int|null $post Optional. Post ID or post object. Defaults to global $post.
* @param bool|null $sample Optional. Whether to force consideration based on sample links.
* If omitted, a sample link is generated if a post object is passed
* with the filter property set to 'sample'.
* @return bool Whether to use a plain permalink structure.
*/
function wp_force_plain_post_permalink( $post = null, $sample = null ) {
if (
null === $sample &&
is_object( $post ) &&
isset( $post->filter ) &&
'sample' === $post->filter
) {
$sample = true;
} else {
$post = get_post( $post );
$sample = null !== $sample ? $sample : false;
}
if ( ! $post ) {
return true;
}
$post_status_obj = get_post_status_object( get_post_status( $post ) );
$post_type_obj = get_post_type_object( get_post_type( $post ) );
if ( ! $post_status_obj || ! $post_type_obj ) {
return true;
}
if (
// Publicly viewable links never have plain permalinks.
is_post_status_viewable( $post_status_obj ) ||
(
// Private posts don't have plain permalinks if the user can read them.
$post_status_obj->private &&
current_user_can( 'read_post', $post->ID )
) ||
// Protected posts don't have plain links if getting a sample URL.
( $post_status_obj->protected && $sample )
) {
return false;
}
return true;
}
/**
* Retrieves the full permalink for the current post or post ID.
*
* This function is an alias for get_permalink().
*
* @since 3.9.0
*
* @see get_permalink()
*
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
* @param bool $leavename Optional. Whether to keep post name or page name. Default false.
* @return string|false The permalink URL. False if the post does not exist.
*/
function get_the_permalink( $post = 0, $leavename = false ) {
return get_permalink( $post, $leavename );
}
/**
* Retrieves the full permalink for the current post or post ID.
*
* @since 1.0.0
*
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
* @param bool $leavename Optional. Whether to keep post name or page name. Default false.
* @return string|false The permalink URL. False if the post does not exist.
*/
function get_permalink( $post = 0, $leavename = false ) {
$rewritecode = array(
'%year%',
'%monthnum%',
'%day%',
'%hour%',
'%minute%',
'%second%',
$leavename ? '' : '%postname%',
'%post_id%',
'%category%',
'%author%',
$leavename ? '' : '%pagename%',
);
if ( is_object( $post ) && isset( $post->filter ) && 'sample' === $post->filter ) {
$sample = true;
} else {
$post = get_post( $post );
$sample = false;
}
if ( empty( $post->ID ) ) {
return false;
}
if ( 'page' === $post->post_type ) {
return get_page_link( $post, $leavename, $sample );
} elseif ( 'attachment' === $post->post_type ) {
return get_attachment_link( $post, $leavename );
} elseif ( in_array( $post->post_type, get_post_types( array( '_builtin' => false ) ), true ) ) {
return get_post_permalink( $post, $leavename, $sample );
}
$permalink = get_option( 'permalink_structure' );
/**
* Filters the permalink structure for a post before token replacement occurs.
*
* Only applies to posts with post_type of 'post'.
*
* @since 3.0.0
*
* @param string $permalink The site's permalink structure.
* @param WP_Post $post The post in question.
* @param bool $leavename Whether to keep the post name.
*/
$permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename );
if (
$permalink &&
! wp_force_plain_post_permalink( $post )
) {
$category = '';
if ( str_contains( $permalink, '%category%' ) ) {
$cats = get_the_category( $post->ID );
if ( $cats ) {
$cats = wp_list_sort(
$cats,
array(
'term_id' => 'ASC',
)
);
/**
* Filters the category that gets used in the %category% permalink token.
*
* @since 3.5.0
*
* @param WP_Term $cat The category to use in the permalink.
* @param array $cats Array of all categories (WP_Term objects) associated with the post.
* @param WP_Post $post The post in question.
*/
$category_object = apply_filters( 'post_link_category', $cats[0], $cats, $post );
$category_object = get_term( $category_object, 'category' );
$category = $category_object->slug;
if ( $category_object->parent ) {
$category = get_category_parents( $category_object->parent, false, '/', true ) . $category;
}
}
/*
* Show default category in permalinks,
* without having to assign it explicitly.
*/
if ( empty( $category ) ) {
$default_category = get_term( get_option( 'default_category' ), 'category' );
if ( $default_category && ! is_wp_error( $default_category ) ) {
$category = $default_category->slug;
}
}
}
$author = '';
if ( str_contains( $permalink, '%author%' ) ) {
$authordata = get_userdata( $post->post_author );
$author = $authordata->user_nicename;
}
/*
* This is not an API call because the permalink is based on the stored post_date value,
* which should be parsed as local time regardless of the default PHP timezone.
*/
$date = explode( ' ', str_replace( array( '-', ':' ), ' ', $post->post_date ) );
$rewritereplace = array(
$date[0],
$date[1],
$date[2],
$date[3],
$date[4],
$date[5],
$post->post_name,
$post->ID,
$category,
$author,
$post->post_name,
);
$permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) );
$permalink = user_trailingslashit( $permalink, 'single' );
} else { // If they're not using the fancy permalink option.
$permalink = home_url( '?p=' . $post->ID );
}
/**
* Filters the permalink for a post.
*
* Only applies to posts with post_type of 'post'.
*
* @since 1.5.0
*
* @param string $permalink The post's permalink.
* @param WP_Post $post The post in question.
* @param bool $leavename Whether to keep the post name.
*/
return apply_filters( 'post_link', $permalink, $post, $leavename );
}
/**
* Retrieves the permalink for a post of a custom post type.
*
* @since 3.0.0
* @since 6.1.0 Returns false if the post does not exist.
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
* @param bool $leavename Optional. Whether to keep post name. Default false.
* @param bool $sample Optional. Is it a sample permalink. Default false.
* @return string|false The post permalink URL. False if the post does not exist.
*/
function get_post_permalink( $post = 0, $leavename = false, $sample = false ) {
global $wp_rewrite;
$post = get_post( $post );
if ( ! $post ) {
return false;
}
$post_link = $wp_rewrite->get_extra_permastruct( $post->post_type );
$slug = $post->post_name;
$force_plain_link = wp_force_plain_post_permalink( $post );
$post_type = get_post_type_object( $post->post_type );
if ( $post_type->hierarchical ) {
$slug = get_page_uri( $post );
}
if ( ! empty( $post_link ) && ( ! $force_plain_link || $sample ) ) {
if ( ! $leavename ) {
$post_link = str_replace( "%$post->post_type%", $slug, $post_link );
}
$post_link = home_url( user_trailingslashit( $post_link ) );
} else {
if ( $post_type->query_var && ( isset( $post->post_status ) && ! $force_plain_link ) ) {
$post_link = add_query_arg( $post_type->query_var, $slug, '' );
} else {
$post_link = add_query_arg(
array(
'post_type' => $post->post_type,
'p' => $post->ID,
),
''
);
}
$post_link = home_url( $post_link );
}
/**
* Filters the permalink for a post of a custom post type.
*
* @since 3.0.0
*
* @param string $post_link The post's permalink.
* @param WP_Post $post The post in question.
* @param bool $leavename Whether to keep the post name.
* @param bool $sample Is it a sample permalink.
*/
return apply_filters( 'post_type_link', $post_link, $post, $leavename, $sample );
}
/**
* Retrieves the permalink for the current page or page ID.
*
* Respects page_on_front. Use this one.
*
* @since 1.5.0
*
* @param int|WP_Post $post Optional. Post ID or object. Default uses the global `$post`.
* @param bool $leavename Optional. Whether to keep the page name. Default false.
* @param bool $sample Optional. Whether it should be treated as a sample permalink.
* Default false.
* @return string The page permalink.
*/
function get_page_link( $post = false, $leavename = false, $sample = false ) {
$post = get_post( $post );
if ( 'page' === get_option( 'show_on_front' ) && (int) get_option( 'page_on_front' ) === $post->ID ) {
$link = home_url( '/' );
} else {
$link = _get_page_link( $post, $leavename, $sample );
}
/**
* Filters the permalink for a page.
*
* @since 1.5.0
*
* @param string $link The page's permalink.
* @param int $post_id The ID of the page.
* @param bool $sample Is it a sample permalink.
*/
return apply_filters( 'page_link', $link, $post->ID, $sample );
}
/**
* Retrieves the page permalink.
*
* Ignores page_on_front. Internal use only.
*
* @since 2.1.0
* @access private
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int|WP_Post $post Optional. Post ID or object. Default uses the global `$post`.
* @param bool $leavename Optional. Whether to keep the page name. Default false.
* @param bool $sample Optional. Whether it should be treated as a sample permalink.
* Default false.
* @return string The page permalink.
*/
function _get_page_link( $post = false, $leavename = false, $sample = false ) {
global $wp_rewrite;
$post = get_post( $post );
$force_plain_link = wp_force_plain_post_permalink( $post );
$link = $wp_rewrite->get_page_permastruct();
if ( ! empty( $link ) && ( ( isset( $post->post_status ) && ! $force_plain_link ) || $sample ) ) {
if ( ! $leavename ) {
$link = str_replace( '%pagename%', get_page_uri( $post ), $link );
}
$link = home_url( $link );
$link = user_trailingslashit( $link, 'page' );
} else {
$link = home_url( '?page_id=' . $post->ID );
}
/**
* Filters the permalink for a non-page_on_front page.
*
* @since 2.1.0
*
* @param string $link The page's permalink.
* @param int $post_id The ID of the page.
*/
return apply_filters( '_get_page_link', $link, $post->ID );
}
/**
* Retrieves the permalink for an attachment.
*
* This can be used in the WordPress Loop or outside of it.
*
* @since 2.0.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int|WP_Post $post Optional. Post ID or object. Default uses the global `$post`.
* @param bool $leavename Optional. Whether to keep the page name. Default false.
* @return string The attachment permalink.
*/
function get_attachment_link( $post = null, $leavename = false ) {
global $wp_rewrite;
$link = false;
$post = get_post( $post );
$force_plain_link = wp_force_plain_post_permalink( $post );
$parent_id = $post->post_parent;
$parent = $parent_id ? get_post( $parent_id ) : false;
$parent_valid = true; // Default for no parent.
if (
$parent_id &&
(
$post->post_parent === $post->ID ||
! $parent ||
! is_post_type_viewable( get_post_type( $parent ) )
)
) {
// Post is either its own parent or parent post unavailable.
$parent_valid = false;
}
if ( $force_plain_link || ! $parent_valid ) {
$link = false;
} elseif ( $wp_rewrite->using_permalinks() && $parent ) {
if ( 'page' === $parent->post_type ) {
$parentlink = _get_page_link( $post->post_parent ); // Ignores page_on_front.
} else {
$parentlink = get_permalink( $post->post_parent );
}
if ( is_numeric( $post->post_name ) || str_contains( get_option( 'permalink_structure' ), '%category%' ) ) {
$name = 'attachment/' . $post->post_name; // <permalink>/<int>/ is paged so we use the explicit attachment marker.
} else {
$name = $post->post_name;
}
if ( ! str_contains( $parentlink, '?' ) ) {
$link = user_trailingslashit( trailingslashit( $parentlink ) . '%postname%' );
}
if ( ! $leavename ) {
$link = str_replace( '%postname%', $name, $link );
}
} elseif ( $wp_rewrite->using_permalinks() && ! $leavename ) {
$link = home_url( user_trailingslashit( $post->post_name ) );
}
if ( ! $link ) {
$link = home_url( '/?attachment_id=' . $post->ID );
}
/**
* Filters the permalink for an attachment.
*
* @since 2.0.0
* @since 5.6.0 Providing an empty string will now disable
* the view attachment page link on the media modal.
*
* @param string $link The attachment's permalink.
* @param int $post_id Attachment ID.
*/
return apply_filters( 'attachment_link', $link, $post->ID );
}
/**
* Retrieves the permalink for the year archives.
*
* @since 1.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int|false $year Integer of year. False for current year.
* @return string The permalink for the specified year archive.
*/
function get_year_link( $year ) {
global $wp_rewrite;
if ( ! $year ) {
$year = current_time( 'Y' );
}
$yearlink = $wp_rewrite->get_year_permastruct();
if ( ! empty( $yearlink ) ) {
$yearlink = str_replace( '%year%', $year, $yearlink );
$yearlink = home_url( user_trailingslashit( $yearlink, 'year' ) );
} else {
$yearlink = home_url( '?m=' . $year );
}
/**
* Filters the year archive permalink.
*
* @since 1.5.0
*
* @param string $yearlink Permalink for the year archive.
* @param int $year Year for the archive.
*/
return apply_filters( 'year_link', $yearlink, $year );
}
/**
* Retrieves the permalink for the month archives with year.
*
* @since 1.0.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int|false $year Integer of year. False for current year.
* @param int|false $month Integer of month. False for current month.
* @return string The permalink for the specified month and year archive.
*/
function get_month_link( $year, $month ) {
global $wp_rewrite;
if ( ! $year ) {
$year = current_time( 'Y' );
}
if ( ! $month ) {
$month = current_time( 'm' );
}
$monthlink = $wp_rewrite->get_month_permastruct();
if ( ! empty( $monthlink ) ) {
$monthlink = str_replace( '%year%', $year, $monthlink );
$monthlink = str_replace( '%monthnum%', zeroise( (int) $month, 2 ), $monthlink );
$monthlink = home_url( user_trailingslashit( $monthlink, 'month' ) );
} else {
$monthlink = home_url( '?m=' . $year . zeroise( $month, 2 ) );
}
/**
* Filters the month archive permalink.
*
* @since 1.5.0
*
* @param string $monthlink Permalink for the month archive.
* @param int $year Year for the archive.
* @param int $month The month for the archive.
*/
return apply_filters( 'month_link', $monthlink, $year, $month );
}
/**
* Retrieves the permalink for the day archives with year and month.
*
* @since 1.0.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int|false $year Integer of year. False for current year.
* @param int|false $month Integer of month. False for current month.
* @param int|false $day Integer of day. False for current day.
* @return string The permalink for the specified day, month, and year archive.
*/
function get_day_link( $year, $month, $day ) {
global $wp_rewrite;
if ( ! $year ) {
$year = current_time( 'Y' );
}
if ( ! $month ) {
$month = current_time( 'm' );
}
if ( ! $day ) {
$day = current_time( 'j' );
}
$daylink = $wp_rewrite->get_day_permastruct();
if ( ! empty( $daylink ) ) {
$daylink = str_replace( '%year%', $year, $daylink );
$daylink = str_replace( '%monthnum%', zeroise( (int) $month, 2 ), $daylink );
$daylink = str_replace( '%day%', zeroise( (int) $day, 2 ), $daylink );
$daylink = home_url( user_trailingslashit( $daylink, 'day' ) );
} else {
$daylink = home_url( '?m=' . $year . zeroise( $month, 2 ) . zeroise( $day, 2 ) );
}
/**
* Filters the day archive permalink.
*
* @since 1.5.0
*
* @param string $daylink Permalink for the day archive.
* @param int $year Year for the archive.
* @param int $month Month for the archive.
* @param int $day The day for the archive.
*/
return apply_filters( 'day_link', $daylink, $year, $month, $day );
}
/**
* Displays the permalink for the feed type.
*
* @since 3.0.0
*
* @param string $anchor The link's anchor text.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
*/
function the_feed_link( $anchor, $feed = '' ) {
$link = '<a href="' . esc_url( get_feed_link( $feed ) ) . '">' . $anchor . '</a>';
/**
* Filters the feed link anchor tag.
*
* @since 3.0.0
*
* @param string $link The complete anchor tag for a feed link.
* @param string $feed The feed type. Possible values include 'rss2', 'atom',
* or an empty string for the default feed type.
*/
echo apply_filters( 'the_feed_link', $link, $feed );
}
/**
* Retrieves the permalink for the feed type.
*
* @since 1.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string The feed permalink.
*/
function get_feed_link( $feed = '' ) {
global $wp_rewrite;
$permalink = $wp_rewrite->get_feed_permastruct();
if ( $permalink ) {
if ( str_contains( $feed, 'comments_' ) ) {
$feed = str_replace( 'comments_', '', $feed );
$permalink = $wp_rewrite->get_comment_feed_permastruct();
}
if ( get_default_feed() === $feed ) {
$feed = '';
}
$permalink = str_replace( '%feed%', $feed, $permalink );
$permalink = preg_replace( '#/+#', '/', "/$permalink" );
$output = home_url( user_trailingslashit( $permalink, 'feed' ) );
} else {
if ( empty( $feed ) ) {
$feed = get_default_feed();
}
if ( str_contains( $feed, 'comments_' ) ) {
$feed = str_replace( 'comments_', 'comments-', $feed );
}
$output = home_url( "?feed={$feed}" );
}
/**
* Filters the feed type permalink.
*
* @since 1.5.0
*
* @param string $output The feed permalink.
* @param string $feed The feed type. Possible values include 'rss2', 'atom',
* or an empty string for the default feed type.
*/
return apply_filters( 'feed_link', $output, $feed );
}
/**
* Retrieves the permalink for the post comments feed.
*
* @since 2.2.0
*
* @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string The permalink for the comments feed for the given post on success, empty string on failure.
*/
function get_post_comments_feed_link( $post_id = 0, $feed = '' ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
$post_id = get_the_ID();
}
if ( empty( $feed ) ) {
$feed = get_default_feed();
}
$post = get_post( $post_id );
// Bail out if the post does not exist.
if ( ! $post instanceof WP_Post ) {
return '';
}
$unattached = 'attachment' === $post->post_type && 0 === (int) $post->post_parent;
if ( get_option( 'permalink_structure' ) ) {
if ( 'page' === get_option( 'show_on_front' ) && (int) get_option( 'page_on_front' ) === $post_id ) {
$url = _get_page_link( $post_id );
} else {
$url = get_permalink( $post_id );
}
if ( $unattached ) {
$url = home_url( '/feed/' );
if ( get_default_feed() !== $feed ) {
$url .= "$feed/";
}
$url = add_query_arg( 'attachment_id', $post_id, $url );
} else {
$url = trailingslashit( $url ) . 'feed';
if ( get_default_feed() !== $feed ) {
$url .= "/$feed";
}
$url = user_trailingslashit( $url, 'single_feed' );
}
} else {
if ( $unattached ) {
$url = add_query_arg(
array(
'feed' => $feed,
'attachment_id' => $post_id,
),
home_url( '/' )
);
} elseif ( 'page' === $post->post_type ) {
$url = add_query_arg(
array(
'feed' => $feed,
'page_id' => $post_id,
),
home_url( '/' )
);
} else {
$url = add_query_arg(
array(
'feed' => $feed,
'p' => $post_id,
),
home_url( '/' )
);
}
}
/**
* Filters the post comments feed permalink.
*
* @since 1.5.1
*
* @param string $url Post comments feed permalink.
*/
return apply_filters( 'post_comments_feed_link', $url );
}
/**
* Displays the comment feed link for a post.
*
* Prints out the comment feed link for a post. Link text is placed in the
* anchor. If no link text is specified, default text is used. If no post ID is
* specified, the current post is used.
*
* @since 2.5.0
*
* @param string $link_text Optional. Descriptive link text. Default 'Comments Feed'.
* @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
*/
function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '' ) {
$url = get_post_comments_feed_link( $post_id, $feed );
if ( empty( $link_text ) ) {
$link_text = __( 'Comments Feed' );
}
$link = '<a href="' . esc_url( $url ) . '">' . $link_text . '</a>';
/**
* Filters the post comment feed link anchor tag.
*
* @since 2.8.0
*
* @param string $link The complete anchor tag for the comment feed link.
* @param int $post_id Post ID.
* @param string $feed The feed type. Possible values include 'rss2', 'atom',
* or an empty string for the default feed type.
*/
echo apply_filters( 'post_comments_feed_link_html', $link, $post_id, $feed );
}
/**
* Retrieves the feed link for a given author.
*
* Returns a link to the feed for all posts by a given author. A specific feed
* can be requested or left blank to get the default feed.
*
* @since 2.5.0
*
* @param int $author_id Author ID.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string Link to the feed for the author specified by $author_id.
*/
function get_author_feed_link( $author_id, $feed = '' ) {
$author_id = (int) $author_id;
$permalink_structure = get_option( 'permalink_structure' );
if ( empty( $feed ) ) {
$feed = get_default_feed();
}
if ( ! $permalink_structure ) {
$link = home_url( "?feed=$feed&author=" . $author_id );
} else {
$link = get_author_posts_url( $author_id );
if ( get_default_feed() === $feed ) {
$feed_link = 'feed';
} else {
$feed_link = "feed/$feed";
}
$link = trailingslashit( $link ) . user_trailingslashit( $feed_link, 'feed' );
}
/**
* Filters the feed link for a given author.
*
* @since 1.5.1
*
* @param string $link The author feed link.
* @param string $feed Feed type. Possible values include 'rss2', 'atom'.
*/
$link = apply_filters( 'author_feed_link', $link, $feed );
return $link;
}
/**
* Retrieves the feed link for a category.
*
* Returns a link to the feed for all posts in a given category. A specific feed
* can be requested or left blank to get the default feed.
*
* @since 2.5.0
*
* @param int|WP_Term|object $cat The ID or category object whose feed link will be retrieved.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string Link to the feed for the category specified by `$cat`.
*/
function get_category_feed_link( $cat, $feed = '' ) {
return get_term_feed_link( $cat, 'category', $feed );
}
/**
* Retrieves the feed link for a term.
*
* Returns a link to the feed for all posts in a given term. A specific feed
* can be requested or left blank to get the default feed.
*
* @since 3.0.0
*
* @param int|WP_Term|object $term The ID or term object whose feed link will be retrieved.
* @param string $taxonomy Optional. Taxonomy of `$term_id`.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string|false Link to the feed for the term specified by `$term` and `$taxonomy`.
*/
function get_term_feed_link( $term, $taxonomy = '', $feed = '' ) {
if ( ! is_object( $term ) ) {
$term = (int) $term;
}
$term = get_term( $term, $taxonomy );
if ( empty( $term ) || is_wp_error( $term ) ) {
return false;
}
$taxonomy = $term->taxonomy;
if ( empty( $feed ) ) {
$feed = get_default_feed();
}
$permalink_structure = get_option( 'permalink_structure' );
if ( ! $permalink_structure ) {
if ( 'category' === $taxonomy ) {
$link = home_url( "?feed=$feed&cat=$term->term_id" );
} elseif ( 'post_tag' === $taxonomy ) {
$link = home_url( "?feed=$feed&tag=$term->slug" );
} else {
$t = get_taxonomy( $taxonomy );
$link = home_url( "?feed=$feed&$t->query_var=$term->slug" );
}
} else {
$link = get_term_link( $term, $term->taxonomy );
if ( get_default_feed() === $feed ) {
$feed_link = 'feed';
} else {
$feed_link = "feed/$feed";
}
$link = trailingslashit( $link ) . user_trailingslashit( $feed_link, 'feed' );
}
if ( 'category' === $taxonomy ) {
/**
* Filters the category feed link.
*
* @since 1.5.1
*
* @param string $link The category feed link.
* @param string $feed Feed type. Possible values include 'rss2', 'atom'.
*/
$link = apply_filters( 'category_feed_link', $link, $feed );
} elseif ( 'post_tag' === $taxonomy ) {
/**
* Filters the post tag feed link.
*
* @since 2.3.0
*
* @param string $link The tag feed link.
* @param string $feed Feed type. Possible values include 'rss2', 'atom'.
*/
$link = apply_filters( 'tag_feed_link', $link, $feed );
} else {
/**
* Filters the feed link for a taxonomy other than 'category' or 'post_tag'.
*
* @since 3.0.0
*
* @param string $link The taxonomy feed link.
* @param string $feed Feed type. Possible values include 'rss2', 'atom'.
* @param string $taxonomy The taxonomy name.
*/
$link = apply_filters( 'taxonomy_feed_link', $link, $feed, $taxonomy );
}
return $link;
}
/**
* Retrieves the permalink for a tag feed.
*
* @since 2.3.0
*
* @param int|WP_Term|object $tag The ID or term object whose feed link will be retrieved.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string The feed permalink for the given tag.
*/
function get_tag_feed_link( $tag, $feed = '' ) {
return get_term_feed_link( $tag, 'post_tag', $feed );
}
/**
* Retrieves the edit link for a tag.
*
* @since 2.7.0
*
* @param int|WP_Term|object $tag The ID or term object whose edit link will be retrieved.
* @param string $taxonomy Optional. Taxonomy slug. Default 'post_tag'.
* @return string The edit tag link URL for the given tag.
*/
function get_edit_tag_link( $tag, $taxonomy = 'post_tag' ) {
/**
* Filters the edit link for a tag (or term in another taxonomy).
*
* @since 2.7.0
*
* @param string $link The term edit link.
*/
return apply_filters( 'get_edit_tag_link', get_edit_term_link( $tag, $taxonomy ) );
}
/**
* Displays or retrieves the edit link for a tag with formatting.
*
* @since 2.7.0
*
* @param string $link Optional. Anchor text. If empty, default is 'Edit This'. Default empty.
* @param string $before Optional. Display before edit link. Default empty.
* @param string $after Optional. Display after edit link. Default empty.
* @param WP_Term $tag Optional. Term object. If null, the queried object will be inspected.
* Default null.
*/
function edit_tag_link( $link = '', $before = '', $after = '', $tag = null ) {
$link = edit_term_link( $link, '', '', $tag, false );
/**
* Filters the anchor tag for the edit link for a tag (or term in another taxonomy).
*
* @since 2.7.0
*
* @param string $link The anchor tag for the edit link.
*/
echo $before . apply_filters( 'edit_tag_link', $link ) . $after;
}
/**
* Retrieves the URL for editing a given term.
*
* @since 3.1.0
* @since 4.5.0 The `$taxonomy` parameter was made optional.
*
* @param int|WP_Term|object $term The ID or term object whose edit link will be retrieved.
* @param string $taxonomy Optional. Taxonomy. Defaults to the taxonomy of the term identified
* by `$term`.
* @param string $object_type Optional. The object type. Used to highlight the proper post type
* menu on the linked page. Defaults to the first object_type associated
* with the taxonomy.
* @return string|null The edit term link URL for the given term, or null on failure.
*/
function get_edit_term_link( $term, $taxonomy = '', $object_type = '' ) {
$term = get_term( $term, $taxonomy );
if ( ! $term || is_wp_error( $term ) ) {
return;
}
$tax = get_taxonomy( $term->taxonomy );
$term_id = $term->term_id;
if ( ! $tax || ! current_user_can( 'edit_term', $term_id ) ) {
return;
}
$args = array(
'taxonomy' => $tax->name,
'tag_ID' => $term_id,
);
if ( $object_type ) {
$args['post_type'] = $object_type;
} elseif ( ! empty( $tax->object_type ) ) {
$args['post_type'] = reset( $tax->object_type );
}
if ( $tax->show_ui ) {
$location = add_query_arg( $args, admin_url( 'term.php' ) );
} else {
$location = '';
}
/**
* Filters the edit link for a term.
*
* @since 3.1.0
*
* @param string $location The edit link.
* @param int $term_id Term ID.
* @param string $taxonomy Taxonomy name.
* @param string $object_type The object type.
*/
return apply_filters( 'get_edit_term_link', $location, $term_id, $taxonomy, $object_type );
}
/**
* Displays or retrieves the edit term link with formatting.
*
* @since 3.1.0
*
* @param string $link Optional. Anchor text. If empty, default is 'Edit This'. Default empty.
* @param string $before Optional. Display before edit link. Default empty.
* @param string $after Optional. Display after edit link. Default empty.
* @param int|WP_Term|null $term Optional. Term ID or object. If null, the queried object will be inspected. Default null.
* @param bool $display Optional. Whether or not to echo the return. Default true.
* @return string|void HTML content.
*/
function edit_term_link( $link = '', $before = '', $after = '', $term = null, $display = true ) {
if ( is_null( $term ) ) {
$term = get_queried_object();
} else {
$term = get_term( $term );
}
if ( ! $term ) {
return;
}
$tax = get_taxonomy( $term->taxonomy );
if ( ! current_user_can( 'edit_term', $term->term_id ) ) {
return;
}
if ( empty( $link ) ) {
$link = __( 'Edit This' );
}
$link = '<a href="' . get_edit_term_link( $term->term_id, $term->taxonomy ) . '">' . $link . '</a>';
/**
* Filters the anchor tag for the edit link of a term.
*
* @since 3.1.0
*
* @param string $link The anchor tag for the edit link.
* @param int $term_id Term ID.
*/
$link = $before . apply_filters( 'edit_term_link', $link, $term->term_id ) . $after;
if ( $display ) {
echo $link;
} else {
return $link;
}
}
/**
* Retrieves the permalink for a search.
*
* @since 3.0.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $query Optional. The query string to use. If empty the current query is used. Default empty.
* @return string The search permalink.
*/
function get_search_link( $query = '' ) {
global $wp_rewrite;
if ( empty( $query ) ) {
$search = get_search_query( false );
} else {
$search = stripslashes( $query );
}
$permastruct = $wp_rewrite->get_search_permastruct();
if ( empty( $permastruct ) ) {
$link = home_url( '?s=' . urlencode( $search ) );
} else {
$search = urlencode( $search );
$search = str_replace( '%2F', '/', $search ); // %2F(/) is not valid within a URL, send it un-encoded.
$link = str_replace( '%search%', $search, $permastruct );
$link = home_url( user_trailingslashit( $link, 'search' ) );
}
/**
* Filters the search permalink.
*
* @since 3.0.0
*
* @param string $link Search permalink.
* @param string $search The URL-encoded search term.
*/
return apply_filters( 'search_link', $link, $search );
}
/**
* Retrieves the permalink for the search results feed.
*
* @since 2.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $search_query Optional. Search query. Default empty.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string The search results feed permalink.
*/
function get_search_feed_link( $search_query = '', $feed = '' ) {
global $wp_rewrite;
$link = get_search_link( $search_query );
if ( empty( $feed ) ) {
$feed = get_default_feed();
}
$permastruct = $wp_rewrite->get_search_permastruct();
if ( empty( $permastruct ) ) {
$link = add_query_arg( 'feed', $feed, $link );
} else {
$link = trailingslashit( $link );
$link .= "feed/$feed/";
}
/**
* Filters the search feed link.
*
* @since 2.5.0
*
* @param string $link Search feed link.
* @param string $feed Feed type. Possible values include 'rss2', 'atom'.
* @param string $type The search type. One of 'posts' or 'comments'.
*/
return apply_filters( 'search_feed_link', $link, $feed, 'posts' );
}
/**
* Retrieves the permalink for the search results comments feed.
*
* @since 2.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $search_query Optional. Search query. Default empty.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string The comments feed search results permalink.
*/
function get_search_comments_feed_link( $search_query = '', $feed = '' ) {
global $wp_rewrite;
if ( empty( $feed ) ) {
$feed = get_default_feed();
}
$link = get_search_feed_link( $search_query, $feed );
$permastruct = $wp_rewrite->get_search_permastruct();
if ( empty( $permastruct ) ) {
$link = add_query_arg( 'feed', 'comments-' . $feed, $link );
} else {
$link = add_query_arg( 'withcomments', 1, $link );
}
/** This filter is documented in wp-includes/link-template.php */
return apply_filters( 'search_feed_link', $link, $feed, 'comments' );
}
/**
* Retrieves the permalink for a post type archive.
*
* @since 3.1.0
* @since 4.5.0 Support for posts was added.
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $post_type Post type.
* @return string|false The post type archive permalink. False if the post type
* does not exist or does not have an archive.
*/
function get_post_type_archive_link( $post_type ) {
global $wp_rewrite;
$post_type_obj = get_post_type_object( $post_type );
if ( ! $post_type_obj ) {
return false;
}
if ( 'post' === $post_type ) {
$show_on_front = get_option( 'show_on_front' );
$page_for_posts = get_option( 'page_for_posts' );
if ( 'page' === $show_on_front && $page_for_posts ) {
$link = get_permalink( $page_for_posts );
} else {
$link = get_home_url();
}
/** This filter is documented in wp-includes/link-template.php */
return apply_filters( 'post_type_archive_link', $link, $post_type );
}
if ( ! $post_type_obj->has_archive ) {
return false;
}
if ( get_option( 'permalink_structure' ) && is_array( $post_type_obj->rewrite ) ) {
$struct = ( true === $post_type_obj->has_archive ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->has_archive;
if ( $post_type_obj->rewrite['with_front'] ) {
$struct = $wp_rewrite->front . $struct;
} else {
$struct = $wp_rewrite->root . $struct;
}
$link = home_url( user_trailingslashit( $struct, 'post_type_archive' ) );
} else {
$link = home_url( '?post_type=' . $post_type );
}
/**
* Filters the post type archive permalink.
*
* @since 3.1.0
*
* @param string $link The post type archive permalink.
* @param string $post_type Post type name.
*/
return apply_filters( 'post_type_archive_link', $link, $post_type );
}
/**
* Retrieves the permalink for a post type archive feed.
*
* @since 3.1.0
*
* @param string $post_type Post type.
* @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
* Default is the value of get_default_feed().
* @return string|false The post type feed permalink. False if the post type
* does not exist or does not have an archive.
*/
function get_post_type_archive_feed_link( $post_type, $feed = '' ) {
$default_feed = get_default_feed();
if ( empty( $feed ) ) {
$feed = $default_feed;
}
$link = get_post_type_archive_link( $post_type );
if ( ! $link ) {
return false;
}
$post_type_obj = get_post_type_object( $post_type );
if ( get_option( 'permalink_structure' ) && is_array( $post_type_obj->rewrite ) && $post_type_obj->rewrite['feeds'] ) {
$link = trailingslashit( $link );
$link .= 'feed/';
if ( $feed !== $default_feed ) {
$link .= "$feed/";
}
} else {
$link = add_query_arg( 'feed', $feed, $link );
}
/**
* Filters the post type archive feed link.
*
* @since 3.1.0
*
* @param string $link The post type archive feed link.
* @param string $feed Feed type. Possible values include 'rss2', 'atom'.
*/
return apply_filters( 'post_type_archive_feed_link', $link, $feed );
}
/**
* Retrieves the URL used for the post preview.
*
* Allows additional query args to be appended.
*
* @since 4.4.0
*
* @param int|WP_Post $post Optional. Post ID or `WP_Post` object. Defaults to global `$post`.
* @param array $query_args Optional. Array of additional query args to be appended to the link.
* Default empty array.
* @param string $preview_link Optional. Base preview link to be used if it should differ from the
* post permalink. Default empty.
* @return string|null URL used for the post preview, or null if the post does not exist.
*/
function get_preview_post_link( $post = null, $query_args = array(), $preview_link = '' ) {
$post = get_post( $post );
if ( ! $post ) {
return;
}
$post_type_object = get_post_type_object( $post->post_type );
if ( is_post_type_viewable( $post_type_object ) ) {
if ( ! $preview_link ) {
$preview_link = set_url_scheme( get_permalink( $post ) );
}
$query_args['preview'] = 'true';
$preview_link = add_query_arg( $query_args, $preview_link );
}
/**
* Filters the URL used for a post preview.
*
* @since 2.0.5
* @since 4.0.0 Added the `$post` parameter.
*
* @param string $preview_link URL used for the post preview.
* @param WP_Post $post Post object.
*/
return apply_filters( 'preview_post_link', $preview_link, $post );
}
/**
* Retrieves the edit post link for post.
*
* Can be used within the WordPress loop or outside of it. Can be used with
* pages, posts, attachments, revisions, global styles, templates, and template parts.
*
* @since 2.3.0
* @since 6.3.0 Adds custom link for wp_navigation post types.
* Adds custom links for wp_template_part and wp_template post types.
*
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
* @param string $context Optional. How to output the '&' character. Default '&'.
* @return string|null The edit post link for the given post. Null if the post type does not exist
* or does not allow an editing UI.
*/
function get_edit_post_link( $post = 0, $context = 'display' ) {
$post = get_post( $post );
if ( ! $post ) {
return;
}
if ( 'revision' === $post->post_type ) {
$action = '';
} elseif ( 'display' === $context ) {
$action = '&action=edit';
} else {
$action = '&action=edit';
}
$post_type_object = get_post_type_object( $post->post_type );
if ( ! $post_type_object ) {
return;
}
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return;
}
$link = '';
if ( 'wp_template' === $post->post_type || 'wp_template_part' === $post->post_type ) {
$slug = urlencode( get_stylesheet() . '//' . $post->post_name );
$link = admin_url( sprintf( $post_type_object->_edit_link, $post->post_type, $slug ) );
} elseif ( 'wp_navigation' === $post->post_type ) {
$link = admin_url( sprintf( $post_type_object->_edit_link, (string) $post->ID ) );
} elseif ( $post_type_object->_edit_link ) {
$link = admin_url( sprintf( $post_type_object->_edit_link . $action, $post->ID ) );
}
/**
* Filters the post edit link.
*
* @since 2.3.0
*
* @param string $link The edit link.
* @param int $post_id Post ID.
* @param string $context The link context. If set to 'display' then ampersands
* are encoded.
*/
return apply_filters( 'get_edit_post_link', $link, $post->ID, $context );
}
/**
* Displays the edit post link for post.
*
* @since 1.0.0
* @since 4.4.0 The `$css_class` argument was added.
*
* @param string $text Optional. Anchor text. If null, default is 'Edit This'. Default null.
* @param string $before Optional. Display before edit link. Default empty.
* @param string $after Optional. Display after edit link. Default empty.
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
* @param string $css_class Optional. Add custom class to link. Default 'post-edit-link'.
*/
function edit_post_link( $text = null, $before = '', $after = '', $post = 0, $css_class = 'post-edit-link' ) {
$post = get_post( $post );
if ( ! $post ) {
return;
}
$url = get_edit_post_link( $post->ID );
if ( ! $url ) {
return;
}
if ( null === $text ) {
$text = __( 'Edit This' );
}
$link = '<a class="' . esc_attr( $css_class ) . '" href="' . esc_url( $url ) . '">' . $text . '</a>';
/**
* Filters the post edit link anchor tag.
*
* @since 2.3.0
*
* @param string $link Anchor tag for the edit link.
* @param int $post_id Post ID.
* @param string $text Anchor text.
*/
echo $before . apply_filters( 'edit_post_link', $link, $post->ID, $text ) . $after;
}
/**
* Retrieves the delete posts link for post.
*
* Can be used within the WordPress loop or outside of it, with any post type.
*
* @since 2.9.0
*
* @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
* @param string $deprecated Not used.
* @param bool $force_delete Optional. Whether to bypass Trash and force deletion. Default false.
* @return string|void The delete post link URL for the given post.
*/
function get_delete_post_link( $post = 0, $deprecated = '', $force_delete = false ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '3.0.0' );
}
$post = get_post( $post );
if ( ! $post ) {
return;
}
$post_type_object = get_post_type_object( $post->post_type );
if ( ! $post_type_object ) {
return;
}
if ( ! current_user_can( 'delete_post', $post->ID ) ) {
return;
}
$action = ( $force_delete || ! EMPTY_TRASH_DAYS ) ? 'delete' : 'trash';
$delete_link = add_query_arg( 'action', $action, admin_url( sprintf( $post_type_object->_edit_link, $post->ID ) ) );
/**
* Filters the post delete link.
*
* @since 2.9.0
*
* @param string $link The delete link.
* @param int $post_id Post ID.
* @param bool $force_delete Whether to bypass the Trash and force deletion. Default false.
*/
return apply_filters( 'get_delete_post_link', wp_nonce_url( $delete_link, "$action-post_{$post->ID}" ), $post->ID, $force_delete );
}
/**
* Retrieves the edit comment link.
*
* @since 2.3.0
* @since 6.7.0 The $context parameter was added.
*
* @param int|WP_Comment $comment_id Optional. Comment ID or WP_Comment object.
* @param string $context Optional. Context in which the URL should be used. Either 'display',
* to include HTML entities, or 'url'. Default 'display'.
* @return string|void The edit comment link URL for the given comment, or void if the comment id does not exist or
* the current user is not allowed to edit it.
*/
function get_edit_comment_link( $comment_id = 0, $context = 'display' ) {
$comment = get_comment( $comment_id );
if ( ! is_object( $comment ) || ! current_user_can( 'edit_comment', $comment->comment_ID ) ) {
return;
}
if ( 'display' === $context ) {
$action = 'comment.php?action=editcomment&c=';
} else {
$action = 'comment.php?action=editcomment&c=';
}
$location = admin_url( $action ) . $comment->comment_ID;
// Ensure the $comment_id variable passed to the filter is always an ID.
$comment_id = (int) $comment->comment_ID;
/**
* Filters the comment edit link.
*
* @since 2.3.0
* @since 6.7.0 The $comment_id and $context parameters are now being passed to the filter.
*
* @param string $location The edit link.
* @param int $comment_id Unique ID of the comment to generate an edit link.
* @param string $context Context to include HTML entities in link. Default 'display'.
*/
return apply_filters( 'get_edit_comment_link', $location, $comment_id, $context );
}
/**
* Displays the edit comment link with formatting.
*
* @since 1.0.0
*
* @param string $text Optional. Anchor text. If null, default is 'Edit This'. Default null.
* @param string $before Optional. Display before edit link. Default empty.
* @param string $after Optional. Display after edit link. Default empty.
*/
function edit_comment_link( $text = null, $before = '', $after = '' ) {
$comment = get_comment();
if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) ) {
return;
}
if ( null === $text ) {
$text = __( 'Edit This' );
}
$link = '<a class="comment-edit-link" href="' . esc_url( get_edit_comment_link( $comment ) ) . '">' . $text . '</a>';
/**
* Filters the comment edit link anchor tag.
*
* @since 2.3.0
*
* @param string $link Anchor tag for the edit link.
* @param string $comment_id Comment ID as a numeric string.
* @param string $text Anchor text.
*/
echo $before . apply_filters( 'edit_comment_link', $link, $comment->comment_ID, $text ) . $after;
}
/**
* Displays the edit bookmark link.
*
* @since 2.7.0
*
* @param int|stdClass $link Optional. Bookmark ID. Default is the ID of the current bookmark.
* @return string|void The edit bookmark link URL.
*/
function get_edit_bookmark_link( $link = 0 ) {
$link = get_bookmark( $link );
if ( ! current_user_can( 'manage_links' ) ) {
return;
}
$location = admin_url( 'link.php?action=edit&link_id=' ) . $link->link_id;
/**
* Filters the bookmark edit link.
*
* @since 2.7.0
*
* @param string $location The edit link.
* @param int $link_id Bookmark ID.
*/
return apply_filters( 'get_edit_bookmark_link', $location, $link->link_id );
}
/**
* Displays the edit bookmark link anchor content.
*
* @since 2.7.0
*
* @param string $link Optional. Anchor text. If empty, default is 'Edit This'. Default empty.
* @param string $before Optional. Display before edit link. Default empty.
* @param string $after Optional. Display after edit link. Default empty.
* @param int $bookmark Optional. Bookmark ID. Default is the current bookmark.
*/
function edit_bookmark_link( $link = '', $before = '', $after = '', $bookmark = null ) {
$bookmark = get_bookmark( $bookmark );
if ( ! current_user_can( 'manage_links' ) ) {
return;
}
if ( empty( $link ) ) {
$link = __( 'Edit This' );
}
$link = '<a href="' . esc_url( get_edit_bookmark_link( $bookmark ) ) . '">' . $link . '</a>';
/**
* Filters the bookmark edit link anchor tag.
*
* @since 2.7.0
*
* @param string $link Anchor tag for the edit link.
* @param int $link_id Bookmark ID.
*/
echo $before . apply_filters( 'edit_bookmark_link', $link, $bookmark->link_id ) . $after;
}
/**
* Retrieves the edit user link.
*
* @since 3.5.0
*
* @param int $user_id Optional. User ID. Defaults to the current user.
* @return string URL to edit user page or empty string.
*/
function get_edit_user_link( $user_id = null ) {
if ( ! $user_id ) {
$user_id = get_current_user_id();
}
if ( empty( $user_id ) || ! current_user_can( 'edit_user', $user_id ) ) {
return '';
}
$user = get_userdata( $user_id );
if ( ! $user ) {
return '';
}
if ( get_current_user_id() === $user->ID ) {
$link = get_edit_profile_url( $user->ID );
} else {
$link = add_query_arg( 'user_id', $user->ID, self_admin_url( 'user-edit.php' ) );
}
/**
* Filters the user edit link.
*
* @since 3.5.0
*
* @param string $link The edit link.
* @param int $user_id User ID.
*/
return apply_filters( 'get_edit_user_link', $link, $user->ID );
}
//
// Navigation links.
//
/**
* Retrieves the previous post that is adjacent to the current post.
*
* @since 1.5.0
*
* @param bool $in_same_term Optional. Whether post should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return WP_Post|null|string Post object if successful. Null if global `$post` is not set.
* Empty string if no corresponding post exists.
*/
function get_previous_post( $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
return get_adjacent_post( $in_same_term, $excluded_terms, true, $taxonomy );
}
/**
* Retrieves the next post that is adjacent to the current post.
*
* @since 1.5.0
*
* @param bool $in_same_term Optional. Whether post should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return WP_Post|null|string Post object if successful. Null if global `$post` is not set.
* Empty string if no corresponding post exists.
*/
function get_next_post( $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
return get_adjacent_post( $in_same_term, $excluded_terms, false, $taxonomy );
}
/**
* Retrieves the adjacent post.
*
* Can either be next or previous post.
*
* @since 2.5.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param bool $in_same_term Optional. Whether post should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty string.
* @param bool $previous Optional. Whether to retrieve previous post.
* Default true.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return WP_Post|null|string Post object if successful. Null if global `$post` is not set.
* Empty string if no corresponding post exists.
*/
function get_adjacent_post( $in_same_term = false, $excluded_terms = '', $previous = true, $taxonomy = 'category' ) {
global $wpdb;
$post = get_post();
if ( ! $post || ! taxonomy_exists( $taxonomy ) ) {
return null;
}
$current_post_date = $post->post_date;
$join = '';
$where = '';
$adjacent = $previous ? 'previous' : 'next';
if ( ! empty( $excluded_terms ) && ! is_array( $excluded_terms ) ) {
// Back-compat, $excluded_terms used to be $excluded_categories with IDs separated by " and ".
if ( str_contains( $excluded_terms, ' and ' ) ) {
_deprecated_argument(
__FUNCTION__,
'3.3.0',
sprintf(
/* translators: %s: The word 'and'. */
__( 'Use commas instead of %s to separate excluded terms.' ),
"'and'"
)
);
$excluded_terms = explode( ' and ', $excluded_terms );
} else {
$excluded_terms = explode( ',', $excluded_terms );
}
$excluded_terms = array_map( 'intval', $excluded_terms );
}
/**
* Filters the IDs of terms excluded from adjacent post queries.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type
* of adjacency, 'next' or 'previous'.
*
* Possible hook names include:
*
* - `get_next_post_excluded_terms`
* - `get_previous_post_excluded_terms`
*
* @since 4.4.0
*
* @param int[]|string $excluded_terms Array of excluded term IDs. Empty string if none were provided.
*/
$excluded_terms = apply_filters( "get_{$adjacent}_post_excluded_terms", $excluded_terms );
if ( $in_same_term || ! empty( $excluded_terms ) ) {
if ( $in_same_term ) {
$join .= " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
$where .= $wpdb->prepare( 'AND tt.taxonomy = %s', $taxonomy );
if ( ! is_object_in_taxonomy( $post->post_type, $taxonomy ) ) {
return '';
}
$term_array = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );
// Remove any exclusions from the term array to include.
$term_array = array_diff( $term_array, (array) $excluded_terms );
$term_array = array_map( 'intval', $term_array );
if ( ! $term_array || is_wp_error( $term_array ) ) {
return '';
}
$where .= ' AND tt.term_id IN (' . implode( ',', $term_array ) . ')';
}
if ( ! empty( $excluded_terms ) ) {
$where .= " AND p.ID NOT IN ( SELECT tr.object_id FROM $wpdb->term_relationships tr LEFT JOIN $wpdb->term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id) WHERE tt.term_id IN (" . implode( ',', array_map( 'intval', $excluded_terms ) ) . ') )';
}
}
// 'post_status' clause depends on the current user.
if ( is_user_logged_in() ) {
$user_id = get_current_user_id();
$post_type_object = get_post_type_object( $post->post_type );
if ( empty( $post_type_object ) ) {
$post_type_cap = $post->post_type;
$read_private_cap = 'read_private_' . $post_type_cap . 's';
} else {
$read_private_cap = $post_type_object->cap->read_private_posts;
}
/*
* Results should include private posts belonging to the current user, or private posts where the
* current user has the 'read_private_posts' cap.
*/
$private_states = get_post_stati( array( 'private' => true ) );
$where .= " AND ( p.post_status = 'publish'";
foreach ( $private_states as $state ) {
if ( current_user_can( $read_private_cap ) ) {
$where .= $wpdb->prepare( ' OR p.post_status = %s', $state );
} else {
$where .= $wpdb->prepare( ' OR (p.post_author = %d AND p.post_status = %s)', $user_id, $state );
}
}
$where .= ' )';
} else {
$where .= " AND p.post_status = 'publish'";
}
$op = $previous ? '<' : '>';
$order = $previous ? 'DESC' : 'ASC';
/**
* Filters the JOIN clause in the SQL for an adjacent post query.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type
* of adjacency, 'next' or 'previous'.
*
* Possible hook names include:
*
* - `get_next_post_join`
* - `get_previous_post_join`
*
* @since 2.5.0
* @since 4.4.0 Added the `$taxonomy` and `$post` parameters.
*
* @param string $join The JOIN clause in the SQL.
* @param bool $in_same_term Whether post should be in the same taxonomy term.
* @param int[]|string $excluded_terms Array of excluded term IDs. Empty string if none were provided.
* @param string $taxonomy Taxonomy. Used to identify the term used when `$in_same_term` is true.
* @param WP_Post $post WP_Post object.
*/
$join = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_term, $excluded_terms, $taxonomy, $post );
/**
* Filters the WHERE clause in the SQL for an adjacent post query.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type
* of adjacency, 'next' or 'previous'.
*
* Possible hook names include:
*
* - `get_next_post_where`
* - `get_previous_post_where`
*
* @since 2.5.0
* @since 4.4.0 Added the `$taxonomy` and `$post` parameters.
*
* @param string $where The `WHERE` clause in the SQL.
* @param bool $in_same_term Whether post should be in the same taxonomy term.
* @param int[]|string $excluded_terms Array of excluded term IDs. Empty string if none were provided.
* @param string $taxonomy Taxonomy. Used to identify the term used when `$in_same_term` is true.
* @param WP_Post $post WP_Post object.
*/
$where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare( "WHERE p.post_date $op %s AND p.post_type = %s $where", $current_post_date, $post->post_type ), $in_same_term, $excluded_terms, $taxonomy, $post );
/**
* Filters the ORDER BY clause in the SQL for an adjacent post query.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type
* of adjacency, 'next' or 'previous'.
*
* Possible hook names include:
*
* - `get_next_post_sort`
* - `get_previous_post_sort`
*
* @since 2.5.0
* @since 4.4.0 Added the `$post` parameter.
* @since 4.9.0 Added the `$order` parameter.
*
* @param string $order_by The `ORDER BY` clause in the SQL.
* @param WP_Post $post WP_Post object.
* @param string $order Sort order. 'DESC' for previous post, 'ASC' for next.
*/
$sort = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1", $post, $order );
$query = "SELECT p.ID FROM $wpdb->posts AS p $join $where $sort";
$key = md5( $query );
$last_changed = wp_cache_get_last_changed( 'posts' );
if ( $in_same_term || ! empty( $excluded_terms ) ) {
$last_changed .= wp_cache_get_last_changed( 'terms' );
}
$cache_key = "adjacent_post:$key:$last_changed";
$result = wp_cache_get( $cache_key, 'post-queries' );
if ( false !== $result ) {
if ( $result ) {
$result = get_post( $result );
}
return $result;
}
$result = $wpdb->get_var( $query );
if ( null === $result ) {
$result = '';
}
wp_cache_set( $cache_key, $result, 'post-queries' );
if ( $result ) {
$result = get_post( $result );
}
return $result;
}
/**
* Retrieves the adjacent post relational link.
*
* Can either be next or previous post relational link.
*
* @since 2.8.0
*
* @param string $title Optional. Link title format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param bool $previous Optional. Whether to display link to previous or next post.
* Default true.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return string|void The adjacent post relational link URL.
*/
function get_adjacent_post_rel_link( $title = '%title', $in_same_term = false, $excluded_terms = '', $previous = true, $taxonomy = 'category' ) {
$post = get_post();
if ( $previous && is_attachment() && $post ) {
$post = get_post( $post->post_parent );
} else {
$post = get_adjacent_post( $in_same_term, $excluded_terms, $previous, $taxonomy );
}
if ( empty( $post ) ) {
return;
}
$post_title = the_title_attribute(
array(
'echo' => false,
'post' => $post,
)
);
if ( empty( $post_title ) ) {
$post_title = $previous ? __( 'Previous Post' ) : __( 'Next Post' );
}
$date = mysql2date( get_option( 'date_format' ), $post->post_date );
$title = str_replace( '%title', $post_title, $title );
$title = str_replace( '%date', $date, $title );
$link = $previous ? "<link rel='prev' title='" : "<link rel='next' title='";
$link .= esc_attr( $title );
$link .= "' href='" . get_permalink( $post ) . "' />\n";
$adjacent = $previous ? 'previous' : 'next';
/**
* Filters the adjacent post relational link.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type
* of adjacency, 'next' or 'previous'.
*
* Possible hook names include:
*
* - `next_post_rel_link`
* - `previous_post_rel_link`
*
* @since 2.8.0
*
* @param string $link The relational link.
*/
return apply_filters( "{$adjacent}_post_rel_link", $link );
}
/**
* Displays the relational links for the posts adjacent to the current post.
*
* @since 2.8.0
*
* @param string $title Optional. Link title format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
*/
function adjacent_posts_rel_link( $title = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
echo get_adjacent_post_rel_link( $title, $in_same_term, $excluded_terms, true, $taxonomy );
echo get_adjacent_post_rel_link( $title, $in_same_term, $excluded_terms, false, $taxonomy );
}
/**
* Displays relational links for the posts adjacent to the current post for single post pages.
*
* This is meant to be attached to actions like 'wp_head'. Do not call this directly in plugins
* or theme templates.
*
* @since 3.0.0
* @since 5.6.0 No longer used in core.
*
* @see adjacent_posts_rel_link()
*/
function adjacent_posts_rel_link_wp_head() {
if ( ! is_single() || is_attachment() ) {
return;
}
adjacent_posts_rel_link();
}
/**
* Displays the relational link for the next post adjacent to the current post.
*
* @since 2.8.0
*
* @see get_adjacent_post_rel_link()
*
* @param string $title Optional. Link title format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
*/
function next_post_rel_link( $title = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
echo get_adjacent_post_rel_link( $title, $in_same_term, $excluded_terms, false, $taxonomy );
}
/**
* Displays the relational link for the previous post adjacent to the current post.
*
* @since 2.8.0
*
* @see get_adjacent_post_rel_link()
*
* @param string $title Optional. Link title format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default true.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
*/
function prev_post_rel_link( $title = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
echo get_adjacent_post_rel_link( $title, $in_same_term, $excluded_terms, true, $taxonomy );
}
/**
* Retrieves the boundary post.
*
* Boundary being either the first or last post by publish date within the constraints specified
* by `$in_same_term` or `$excluded_terms`.
*
* @since 2.8.0
*
* @param bool $in_same_term Optional. Whether returned post should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param bool $start Optional. Whether to retrieve first or last post.
* Default true.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return array|null Array containing the boundary post object if successful, null otherwise.
*/
function get_boundary_post( $in_same_term = false, $excluded_terms = '', $start = true, $taxonomy = 'category' ) {
$post = get_post();
if ( ! $post || ! is_single() || is_attachment() || ! taxonomy_exists( $taxonomy ) ) {
return null;
}
$query_args = array(
'posts_per_page' => 1,
'order' => $start ? 'ASC' : 'DESC',
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
);
$term_array = array();
if ( ! is_array( $excluded_terms ) ) {
if ( ! empty( $excluded_terms ) ) {
$excluded_terms = explode( ',', $excluded_terms );
} else {
$excluded_terms = array();
}
}
if ( $in_same_term || ! empty( $excluded_terms ) ) {
if ( $in_same_term ) {
$term_array = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );
}
if ( ! empty( $excluded_terms ) ) {
$excluded_terms = array_map( 'intval', $excluded_terms );
$excluded_terms = array_diff( $excluded_terms, $term_array );
$inverse_terms = array();
foreach ( $excluded_terms as $excluded_term ) {
$inverse_terms[] = $excluded_term * -1;
}
$excluded_terms = $inverse_terms;
}
$query_args['tax_query'] = array(
array(
'taxonomy' => $taxonomy,
'terms' => array_merge( $term_array, $excluded_terms ),
),
);
}
return get_posts( $query_args );
}
/**
* Retrieves the previous post link that is adjacent to the current post.
*
* @since 3.7.0
*
* @param string $format Optional. Link anchor format. Default '« %link'.
* @param string $link Optional. Link permalink format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return string The link URL of the previous post in relation to the current post.
*/
function get_previous_post_link( $format = '« %link', $link = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
return get_adjacent_post_link( $format, $link, $in_same_term, $excluded_terms, true, $taxonomy );
}
/**
* Displays the previous post link that is adjacent to the current post.
*
* @since 1.5.0
*
* @see get_previous_post_link()
*
* @param string $format Optional. Link anchor format. Default '« %link'.
* @param string $link Optional. Link permalink format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
*/
function previous_post_link( $format = '« %link', $link = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
echo get_previous_post_link( $format, $link, $in_same_term, $excluded_terms, $taxonomy );
}
/**
* Retrieves the next post link that is adjacent to the current post.
*
* @since 3.7.0
*
* @param string $format Optional. Link anchor format. Default '« %link'.
* @param string $link Optional. Link permalink format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return string The link URL of the next post in relation to the current post.
*/
function get_next_post_link( $format = '%link »', $link = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
return get_adjacent_post_link( $format, $link, $in_same_term, $excluded_terms, false, $taxonomy );
}
/**
* Displays the next post link that is adjacent to the current post.
*
* @since 1.5.0
*
* @see get_next_post_link()
*
* @param string $format Optional. Link anchor format. Default '« %link'.
* @param string $link Optional. Link permalink format. Default '%title'.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs.
* Default empty.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
*/
function next_post_link( $format = '%link »', $link = '%title', $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
echo get_next_post_link( $format, $link, $in_same_term, $excluded_terms, $taxonomy );
}
/**
* Retrieves the adjacent post link.
*
* Can be either next post link or previous.
*
* @since 3.7.0
*
* @param string $format Link anchor format.
* @param string $link Link permalink format.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded terms IDs.
* Default empty.
* @param bool $previous Optional. Whether to display link to previous or next post.
* Default true.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
* @return string The link URL of the previous or next post in relation to the current post.
*/
function get_adjacent_post_link( $format, $link, $in_same_term = false, $excluded_terms = '', $previous = true, $taxonomy = 'category' ) {
if ( $previous && is_attachment() ) {
$post = get_post( get_post()->post_parent );
} else {
$post = get_adjacent_post( $in_same_term, $excluded_terms, $previous, $taxonomy );
}
if ( ! $post ) {
$output = '';
} else {
$title = $post->post_title;
if ( empty( $post->post_title ) ) {
$title = $previous ? __( 'Previous Post' ) : __( 'Next Post' );
}
/** This filter is documented in wp-includes/post-template.php */
$title = apply_filters( 'the_title', $title, $post->ID );
$date = mysql2date( get_option( 'date_format' ), $post->post_date );
$rel = $previous ? 'prev' : 'next';
$string = '<a href="' . get_permalink( $post ) . '" rel="' . $rel . '">';
$inlink = str_replace( '%title', $title, $link );
$inlink = str_replace( '%date', $date, $inlink );
$inlink = $string . $inlink . '</a>';
$output = str_replace( '%link', $inlink, $format );
}
$adjacent = $previous ? 'previous' : 'next';
/**
* Filters the adjacent post link.
*
* The dynamic portion of the hook name, `$adjacent`, refers to the type
* of adjacency, 'next' or 'previous'.
*
* Possible hook names include:
*
* - `next_post_link`
* - `previous_post_link`
*
* @since 2.6.0
* @since 4.2.0 Added the `$adjacent` parameter.
*
* @param string $output The adjacent post link.
* @param string $format Link anchor format.
* @param string $link Link permalink format.
* @param WP_Post|string $post The adjacent post. Empty string if no corresponding post exists.
* @param string $adjacent Whether the post is previous or next.
*/
return apply_filters( "{$adjacent}_post_link", $output, $format, $link, $post, $adjacent );
}
/**
* Displays the adjacent post link.
*
* Can be either next post link or previous.
*
* @since 2.5.0
*
* @param string $format Link anchor format.
* @param string $link Link permalink format.
* @param bool $in_same_term Optional. Whether link should be in the same taxonomy term.
* Default false.
* @param int[]|string $excluded_terms Optional. Array or comma-separated list of excluded category IDs.
* Default empty.
* @param bool $previous Optional. Whether to display link to previous or next post.
* Default true.
* @param string $taxonomy Optional. Taxonomy, if `$in_same_term` is true. Default 'category'.
*/
function adjacent_post_link( $format, $link, $in_same_term = false, $excluded_terms = '', $previous = true, $taxonomy = 'category' ) {
echo get_adjacent_post_link( $format, $link, $in_same_term, $excluded_terms, $previous, $taxonomy );
}
/**
* Retrieves the link for a page number.
*
* @since 1.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int $pagenum Optional. Page number. Default 1.
* @param bool $escape Optional. Whether to escape the URL for display, with esc_url().
* If set to false, prepares the URL with sanitize_url(). Default true.
* @return string The link URL for the given page number.
*/
function get_pagenum_link( $pagenum = 1, $escape = true ) {
global $wp_rewrite;
$pagenum = (int) $pagenum;
$request = remove_query_arg( 'paged' );
$home_root = parse_url( home_url() );
$home_root = ( isset( $home_root['path'] ) ) ? $home_root['path'] : '';
$home_root = preg_quote( $home_root, '|' );
$request = preg_replace( '|^' . $home_root . '|i', '', $request );
$request = preg_replace( '|^/+|', '', $request );
if ( ! $wp_rewrite->using_permalinks() || is_admin() ) {
$base = trailingslashit( get_bloginfo( 'url' ) );
if ( $pagenum > 1 ) {
$result = add_query_arg( 'paged', $pagenum, $base . $request );
} else {
$result = $base . $request;
}
} else {
$qs_regex = '|\?.*?$|';
preg_match( $qs_regex, $request, $qs_match );
$parts = array();
$parts[] = untrailingslashit( get_bloginfo( 'url' ) );
if ( ! empty( $qs_match[0] ) ) {
$query_string = $qs_match[0];
$request = preg_replace( $qs_regex, '', $request );
} else {
$query_string = '';
}
$request = preg_replace( "|$wp_rewrite->pagination_base/\d+/?$|", '', $request );
$request = preg_replace( '|^' . preg_quote( $wp_rewrite->index, '|' ) . '|i', '', $request );
$request = ltrim( $request, '/' );
if ( $wp_rewrite->using_index_permalinks() && ( $pagenum > 1 || '' !== $request ) ) {
$parts[] = $wp_rewrite->index;
}
$parts[] = untrailingslashit( $request );
if ( $pagenum > 1 ) {
$parts[] = $wp_rewrite->pagination_base;
$parts[] = $pagenum;
}
$result = user_trailingslashit( implode( '/', array_filter( $parts ) ), 'paged' );
if ( ! empty( $query_string ) ) {
$result .= $query_string;
}
}
/**
* Filters the page number link for the current request.
*
* @since 2.5.0
* @since 5.2.0 Added the `$pagenum` argument.
*
* @param string $result The page number link.
* @param int $pagenum The page number.
*/
$result = apply_filters( 'get_pagenum_link', $result, $pagenum );
if ( $escape ) {
return esc_url( $result );
} else {
return sanitize_url( $result );
}
}
/**
* Retrieves the next posts page link.
*
* Backported from 2.1.3 to 2.0.10.
*
* @since 2.0.10
*
* @global int $paged
*
* @param int $max_page Optional. Max pages. Default 0.
* @return string|void The link URL for next posts page.
*/
function get_next_posts_page_link( $max_page = 0 ) {
global $paged;
if ( ! is_single() ) {
if ( ! $paged ) {
$paged = 1;
}
$next_page = (int) $paged + 1;
if ( ! $max_page || $max_page >= $next_page ) {
return get_pagenum_link( $next_page );
}
}
}
/**
* Displays or retrieves the next posts page link.
*
* @since 0.71
*
* @param int $max_page Optional. Max pages. Default 0.
* @param bool $display Optional. Whether to echo the link. Default true.
* @return string|void The link URL for next posts page if `$display = false`.
*/
function next_posts( $max_page = 0, $display = true ) {
$link = get_next_posts_page_link( $max_page );
$output = $link ? esc_url( $link ) : '';
if ( $display ) {
echo $output;
} else {
return $output;
}
}
/**
* Retrieves the next posts page link.
*
* @since 2.7.0
*
* @global int $paged
* @global WP_Query $wp_query WordPress Query object.
*
* @param string $label Content for link text.
* @param int $max_page Optional. Max pages. Default 0.
* @return string|void HTML-formatted next posts page link.
*/
function get_next_posts_link( $label = null, $max_page = 0 ) {
global $paged, $wp_query;
if ( ! $max_page ) {
$max_page = $wp_query->max_num_pages;
}
if ( ! $paged ) {
$paged = 1;
}
$next_page = (int) $paged + 1;
if ( null === $label ) {
$label = __( 'Next Page »' );
}
if ( ! is_single() && ( $next_page <= $max_page ) ) {
/**
* Filters the anchor tag attributes for the next posts page link.
*
* @since 2.7.0
*
* @param string $attributes Attributes for the anchor tag.
*/
$attr = apply_filters( 'next_posts_link_attributes', '' );
return sprintf(
'<a href="%1$s" %2$s>%3$s</a>',
next_posts( $max_page, false ),
$attr,
preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $label )
);
}
}
/**
* Displays the next posts page link.
*
* @since 0.71
*
* @param string $label Content for link text.
* @param int $max_page Optional. Max pages. Default 0.
*/
function next_posts_link( $label = null, $max_page = 0 ) {
echo get_next_posts_link( $label, $max_page );
}
/**
* Retrieves the previous posts page link.
*
* Will only return string, if not on a single page or post.
*
* Backported to 2.0.10 from 2.1.3.
*
* @since 2.0.10
*
* @global int $paged
*
* @return string|void The link for the previous posts page.
*/
function get_previous_posts_page_link() {
global $paged;
if ( ! is_single() ) {
$previous_page = (int) $paged - 1;
if ( $previous_page < 1 ) {
$previous_page = 1;
}
return get_pagenum_link( $previous_page );
}
}
/**
* Displays or retrieves the previous posts page link.
*
* @since 0.71
*
* @param bool $display Optional. Whether to echo the link. Default true.
* @return string|void The previous posts page link if `$display = false`.
*/
function previous_posts( $display = true ) {
$output = esc_url( get_previous_posts_page_link() );
if ( $display ) {
echo $output;
} else {
return $output;
}
}
/**
* Retrieves the previous posts page link.
*
* @since 2.7.0
*
* @global int $paged
*
* @param string $label Optional. Previous page link text.
* @return string|void HTML-formatted previous page link.
*/
function get_previous_posts_link( $label = null ) {
global $paged;
if ( null === $label ) {
$label = __( '« Previous Page' );
}
if ( ! is_single() && $paged > 1 ) {
/**
* Filters the anchor tag attributes for the previous posts page link.
*
* @since 2.7.0
*
* @param string $attributes Attributes for the anchor tag.
*/
$attr = apply_filters( 'previous_posts_link_attributes', '' );
return sprintf(
'<a href="%1$s" %2$s>%3$s</a>',
previous_posts( false ),
$attr,
preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $label )
);
}
}
/**
* Displays the previous posts page link.
*
* @since 0.71
*
* @param string $label Optional. Previous page link text.
*/
function previous_posts_link( $label = null ) {
echo get_previous_posts_link( $label );
}
/**
* Retrieves the post pages link navigation for previous and next pages.
*
* @since 2.8.0
*
* @global WP_Query $wp_query WordPress Query object.
*
* @param string|array $args {
* Optional. Arguments to build the post pages link navigation.
*
* @type string $sep Separator character. Default '—'.
* @type string $prelabel Link text to display for the previous page link.
* Default '« Previous Page'.
* @type string $nxtlabel Link text to display for the next page link.
* Default 'Next Page »'.
* }
* @return string The posts link navigation.
*/
function get_posts_nav_link( $args = array() ) {
global $wp_query;
$return = '';
if ( ! is_singular() ) {
$defaults = array(
'sep' => ' — ',
'prelabel' => __( '« Previous Page' ),
'nxtlabel' => __( 'Next Page »' ),
);
$args = wp_parse_args( $args, $defaults );
$max_num_pages = $wp_query->max_num_pages;
$paged = get_query_var( 'paged' );
// Only have sep if there's both prev and next results.
if ( $paged < 2 || $paged >= $max_num_pages ) {
$args['sep'] = '';
}
if ( $max_num_pages > 1 ) {
$return = get_previous_posts_link( $args['prelabel'] );
$return .= preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $args['sep'] );
$return .= get_next_posts_link( $args['nxtlabel'] );
}
}
return $return;
}
/**
* Displays the post pages link navigation for previous and next pages.
*
* @since 0.71
*
* @param string $sep Optional. Separator for posts navigation links. Default empty.
* @param string $prelabel Optional. Label for previous pages. Default empty.
* @param string $nxtlabel Optional Label for next pages. Default empty.
*/
function posts_nav_link( $sep = '', $prelabel = '', $nxtlabel = '' ) {
$args = array_filter( compact( 'sep', 'prelabel', 'nxtlabel' ) );
echo get_posts_nav_link( $args );
}
/**
* Retrieves the navigation to next/previous post, when applicable.
*
* @since 4.1.0
* @since 4.4.0 Introduced the `in_same_term`, `excluded_terms`, and `taxonomy` arguments.
* @since 5.3.0 Added the `aria_label` parameter.
* @since 5.5.0 Added the `class` parameter.
*
* @param array $args {
* Optional. Default post navigation arguments. Default empty array.
*
* @type string $prev_text Anchor text to display in the previous post link.
* Default '%title'.
* @type string $next_text Anchor text to display in the next post link.
* Default '%title'.
* @type bool $in_same_term Whether link should be in the same taxonomy term.
* Default false.
* @type int[]|string $excluded_terms Array or comma-separated list of excluded term IDs.
* Default empty.
* @type string $taxonomy Taxonomy, if `$in_same_term` is true. Default 'category'.
* @type string $screen_reader_text Screen reader text for the nav element.
* Default 'Post navigation'.
* @type string $aria_label ARIA label text for the nav element. Default 'Posts'.
* @type string $class Custom class for the nav element. Default 'post-navigation'.
* }
* @return string Markup for post links.
*/
function get_the_post_navigation( $args = array() ) {
// Make sure the nav element has an aria-label attribute: fallback to the screen reader text.
if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) {
$args['aria_label'] = $args['screen_reader_text'];
}
$args = wp_parse_args(
$args,
array(
'prev_text' => '%title',
'next_text' => '%title',
'in_same_term' => false,
'excluded_terms' => '',
'taxonomy' => 'category',
'screen_reader_text' => __( 'Post navigation' ),
'aria_label' => __( 'Posts' ),
'class' => 'post-navigation',
)
);
$navigation = '';
$previous = get_previous_post_link(
'<div class="nav-previous">%link</div>',
$args['prev_text'],
$args['in_same_term'],
$args['excluded_terms'],
$args['taxonomy']
);
$next = get_next_post_link(
'<div class="nav-next">%link</div>',
$args['next_text'],
$args['in_same_term'],
$args['excluded_terms'],
$args['taxonomy']
);
// Only add markup if there's somewhere to navigate to.
if ( $previous || $next ) {
$navigation = _navigation_markup( $previous . $next, $args['class'], $args['screen_reader_text'], $args['aria_label'] );
}
return $navigation;
}
/**
* Displays the navigation to next/previous post, when applicable.
*
* @since 4.1.0
*
* @param array $args Optional. See get_the_post_navigation() for available arguments.
* Default empty array.
*/
function the_post_navigation( $args = array() ) {
echo get_the_post_navigation( $args );
}
/**
* Returns the navigation to next/previous set of posts, when applicable.
*
* @since 4.1.0
* @since 5.3.0 Added the `aria_label` parameter.
* @since 5.5.0 Added the `class` parameter.
*
* @global WP_Query $wp_query WordPress Query object.
*
* @param array $args {
* Optional. Default posts navigation arguments. Default empty array.
*
* @type string $prev_text Anchor text to display in the previous posts link.
* Default 'Older posts'.
* @type string $next_text Anchor text to display in the next posts link.
* Default 'Newer posts'.
* @type string $screen_reader_text Screen reader text for the nav element.
* Default 'Posts navigation'.
* @type string $aria_label ARIA label text for the nav element. Default 'Posts'.
* @type string $class Custom class for the nav element. Default 'posts-navigation'.
* }
* @return string Markup for posts links.
*/
function get_the_posts_navigation( $args = array() ) {
global $wp_query;
$navigation = '';
// Don't print empty markup if there's only one page.
if ( $wp_query->max_num_pages > 1 ) {
// Make sure the nav element has an aria-label attribute: fallback to the screen reader text.
if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) {
$args['aria_label'] = $args['screen_reader_text'];
}
$args = wp_parse_args(
$args,
array(
'prev_text' => __( 'Older posts' ),
'next_text' => __( 'Newer posts' ),
'screen_reader_text' => __( 'Posts navigation' ),
'aria_label' => __( 'Posts' ),
'class' => 'posts-navigation',
)
);
$next_link = get_previous_posts_link( $args['next_text'] );
$prev_link = get_next_posts_link( $args['prev_text'] );
if ( $prev_link ) {
$navigation .= '<div class="nav-previous">' . $prev_link . '</div>';
}
if ( $next_link ) {
$navigation .= '<div class="nav-next">' . $next_link . '</div>';
}
$navigation = _navigation_markup( $navigation, $args['class'], $args['screen_reader_text'], $args['aria_label'] );
}
return $navigation;
}
/**
* Displays the navigation to next/previous set of posts, when applicable.
*
* @since 4.1.0
*
* @param array $args Optional. See get_the_posts_navigation() for available arguments.
* Default empty array.
*/
function the_posts_navigation( $args = array() ) {
echo get_the_posts_navigation( $args );
}
/**
* Retrieves a paginated navigation to next/previous set of posts, when applicable.
*
* @since 4.1.0
* @since 5.3.0 Added the `aria_label` parameter.
* @since 5.5.0 Added the `class` parameter.
*
* @global WP_Query $wp_query WordPress Query object.
*
* @param array $args {
* Optional. Default pagination arguments, see paginate_links().
*
* @type string $screen_reader_text Screen reader text for navigation element.
* Default 'Posts pagination'.
* @type string $aria_label ARIA label text for the nav element. Default 'Posts pagination'.
* @type string $class Custom class for the nav element. Default 'pagination'.
* }
* @return string Markup for pagination links.
*/
function get_the_posts_pagination( $args = array() ) {
global $wp_query;
$navigation = '';
// Don't print empty markup if there's only one page.
if ( $wp_query->max_num_pages > 1 ) {
// Make sure the nav element has an aria-label attribute: fallback to the screen reader text.
if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) {
$args['aria_label'] = $args['screen_reader_text'];
}
$args = wp_parse_args(
$args,
array(
'mid_size' => 1,
'prev_text' => _x( 'Previous', 'previous set of posts' ),
'next_text' => _x( 'Next', 'next set of posts' ),
'screen_reader_text' => __( 'Posts pagination' ),
'aria_label' => __( 'Posts pagination' ),
'class' => 'pagination',
)
);
/**
* Filters the arguments for posts pagination links.
*
* @since 6.1.0
*
* @param array $args {
* Optional. Default pagination arguments, see paginate_links().
*
* @type string $screen_reader_text Screen reader text for navigation element.
* Default 'Posts navigation'.
* @type string $aria_label ARIA label text for the nav element. Default 'Posts'.
* @type string $class Custom class for the nav element. Default 'pagination'.
* }
*/
$args = apply_filters( 'the_posts_pagination_args', $args );
// Make sure we get a string back. Plain is the next best thing.
if ( isset( $args['type'] ) && 'array' === $args['type'] ) {
$args['type'] = 'plain';
}
// Set up paginated links.
$links = paginate_links( $args );
if ( $links ) {
$navigation = _navigation_markup( $links, $args['class'], $args['screen_reader_text'], $args['aria_label'] );
}
}
return $navigation;
}
/**
* Displays a paginated navigation to next/previous set of posts, when applicable.
*
* @since 4.1.0
*
* @param array $args Optional. See get_the_posts_pagination() for available arguments.
* Default empty array.
*/
function the_posts_pagination( $args = array() ) {
echo get_the_posts_pagination( $args );
}
/**
* Wraps passed links in navigational markup.
*
* @since 4.1.0
* @since 5.3.0 Added the `aria_label` parameter.
* @access private
*
* @param string $links Navigational links.
* @param string $css_class Optional. Custom class for the nav element.
* Default 'posts-navigation'.
* @param string $screen_reader_text Optional. Screen reader text for the nav element.
* Default 'Posts navigation'.
* @param string $aria_label Optional. ARIA label for the nav element.
* Defaults to the value of `$screen_reader_text`.
* @return string Navigation template tag.
*/
function _navigation_markup( $links, $css_class = 'posts-navigation', $screen_reader_text = '', $aria_label = '' ) {
if ( empty( $screen_reader_text ) ) {
$screen_reader_text = /* translators: Hidden accessibility text. */ __( 'Posts navigation' );
}
if ( empty( $aria_label ) ) {
$aria_label = $screen_reader_text;
}
$template = '
<nav class="navigation %1$s" aria-label="%4$s">
<h2 class="screen-reader-text">%2$s</h2>
<div class="nav-links">%3$s</div>
</nav>';
/**
* Filters the navigation markup template.
*
* Note: The filtered template HTML must contain specifiers for the navigation
* class (%1$s), the screen-reader-text value (%2$s), placement of the navigation
* links (%3$s), and ARIA label text if screen-reader-text does not fit that (%4$s):
*
* <nav class="navigation %1$s" aria-label="%4$s">
* <h2 class="screen-reader-text">%2$s</h2>
* <div class="nav-links">%3$s</div>
* </nav>
*
* @since 4.4.0
*
* @param string $template The default template.
* @param string $css_class The class passed by the calling function.
*/
$template = apply_filters( 'navigation_markup_template', $template, $css_class );
return sprintf( $template, sanitize_html_class( $css_class ), esc_html( $screen_reader_text ), $links, esc_attr( $aria_label ) );
}
/**
* Retrieves the comments page number link.
*
* @since 2.7.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int $pagenum Optional. Page number. Default 1.
* @param int $max_page Optional. The maximum number of comment pages. Default 0.
* @return string The comments page number link URL.
*/
function get_comments_pagenum_link( $pagenum = 1, $max_page = 0 ) {
global $wp_rewrite;
$pagenum = (int) $pagenum;
$max_page = (int) $max_page;
$result = get_permalink();
if ( 'newest' === get_option( 'default_comments_page' ) ) {
if ( $pagenum !== $max_page ) {
if ( $wp_rewrite->using_permalinks() ) {
$result = user_trailingslashit( trailingslashit( $result ) . $wp_rewrite->comments_pagination_base . '-' . $pagenum, 'commentpaged' );
} else {
$result = add_query_arg( 'cpage', $pagenum, $result );
}
}
} elseif ( $pagenum > 1 ) {
if ( $wp_rewrite->using_permalinks() ) {
$result = user_trailingslashit( trailingslashit( $result ) . $wp_rewrite->comments_pagination_base . '-' . $pagenum, 'commentpaged' );
} else {
$result = add_query_arg( 'cpage', $pagenum, $result );
}
}
$result .= '#comments';
/**
* Filters the comments page number link for the current request.
*
* @since 2.7.0
*
* @param string $result The comments page number link.
*/
return apply_filters( 'get_comments_pagenum_link', $result );
}
/**
* Retrieves the link to the next comments page.
*
* @since 2.7.1
* @since 6.7.0 Added the `page` parameter.
*
* @global WP_Query $wp_query WordPress Query object.
*
* @param string $label Optional. Label for link text. Default empty.
* @param int $max_page Optional. Max page. Default 0.
* @param int|null $page Optional. Page number. Default null.
* @return string|void HTML-formatted link for the next page of comments.
*/
function get_next_comments_link( $label = '', $max_page = 0, $page = null ) {
global $wp_query;
if ( ! is_singular() ) {
return;
}
if ( is_null( $page ) ) {
$page = get_query_var( 'cpage' );
}
if ( ! $page ) {
$page = 1;
}
$next_page = (int) $page + 1;
if ( empty( $max_page ) ) {
$max_page = $wp_query->max_num_comment_pages;
}
if ( empty( $max_page ) ) {
$max_page = get_comment_pages_count();
}
if ( $next_page > $max_page ) {
return;
}
if ( empty( $label ) ) {
$label = __( 'Newer Comments »' );
}
/**
* Filters the anchor tag attributes for the next comments page link.
*
* @since 2.7.0
*
* @param string $attributes Attributes for the anchor tag.
*/
$attr = apply_filters( 'next_comments_link_attributes', '' );
return sprintf(
'<a href="%1$s" %2$s>%3$s</a>',
esc_url( get_comments_pagenum_link( $next_page, $max_page ) ),
$attr,
preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $label )
);
}
/**
* Displays the link to the next comments page.
*
* @since 2.7.0
*
* @param string $label Optional. Label for link text. Default empty.
* @param int $max_page Optional. Max page. Default 0.
*/
function next_comments_link( $label = '', $max_page = 0 ) {
echo get_next_comments_link( $label, $max_page );
}
/**
* Retrieves the link to the previous comments page.
*
* @since 2.7.1
* @since 6.7.0 Added the `page` parameter.
*
* @param string $label Optional. Label for comments link text. Default empty.
* @param int|null $page Optional. Page number. Default null.
* @return string|void HTML-formatted link for the previous page of comments.
*/
function get_previous_comments_link( $label = '', $page = null ) {
if ( ! is_singular() ) {
return;
}
if ( is_null( $page ) ) {
$page = get_query_var( 'cpage' );
}
if ( (int) $page <= 1 ) {
return;
}
$previous_page = (int) $page - 1;
if ( empty( $label ) ) {
$label = __( '« Older Comments' );
}
/**
* Filters the anchor tag attributes for the previous comments page link.
*
* @since 2.7.0
*
* @param string $attributes Attributes for the anchor tag.
*/
$attr = apply_filters( 'previous_comments_link_attributes', '' );
return sprintf(
'<a href="%1$s" %2$s>%3$s</a>',
esc_url( get_comments_pagenum_link( $previous_page ) ),
$attr,
preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $label )
);
}
/**
* Displays the link to the previous comments page.
*
* @since 2.7.0
*
* @param string $label Optional. Label for comments link text. Default empty.
*/
function previous_comments_link( $label = '' ) {
echo get_previous_comments_link( $label );
}
/**
* Displays or retrieves pagination links for the comments on the current post.
*
* @see paginate_links()
* @since 2.7.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string|array $args Optional args. See paginate_links(). Default empty array.
* @return void|string|array Void if 'echo' argument is true and 'type' is not an array,
* or if the query is not for an existing single post of any post type.
* Otherwise, markup for comment page links or array of comment page links,
* depending on 'type' argument.
*/
function paginate_comments_links( $args = array() ) {
global $wp_rewrite;
if ( ! is_singular() ) {
return;
}
$page = get_query_var( 'cpage' );
if ( ! $page ) {
$page = 1;
}
$max_page = get_comment_pages_count();
$defaults = array(
'base' => add_query_arg( 'cpage', '%#%' ),
'format' => '',
'total' => $max_page,
'current' => $page,
'echo' => true,
'type' => 'plain',
'add_fragment' => '#comments',
);
if ( $wp_rewrite->using_permalinks() ) {
$defaults['base'] = user_trailingslashit( trailingslashit( get_permalink() ) . $wp_rewrite->comments_pagination_base . '-%#%', 'commentpaged' );
}
$args = wp_parse_args( $args, $defaults );
$page_links = paginate_links( $args );
if ( $args['echo'] && 'array' !== $args['type'] ) {
echo $page_links;
} else {
return $page_links;
}
}
/**
* Retrieves navigation to next/previous set of comments, when applicable.
*
* @since 4.4.0
* @since 5.3.0 Added the `aria_label` parameter.
* @since 5.5.0 Added the `class` parameter.
*
* @param array $args {
* Optional. Default comments navigation arguments.
*
* @type string $prev_text Anchor text to display in the previous comments link.
* Default 'Older comments'.
* @type string $next_text Anchor text to display in the next comments link.
* Default 'Newer comments'.
* @type string $screen_reader_text Screen reader text for the nav element. Default 'Comments navigation'.
* @type string $aria_label ARIA label text for the nav element. Default 'Comments'.
* @type string $class Custom class for the nav element. Default 'comment-navigation'.
* }
* @return string Markup for comments links.
*/
function get_the_comments_navigation( $args = array() ) {
$navigation = '';
// Are there comments to navigate through?
if ( get_comment_pages_count() > 1 ) {
// Make sure the nav element has an aria-label attribute: fallback to the screen reader text.
if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) {
$args['aria_label'] = $args['screen_reader_text'];
}
$args = wp_parse_args(
$args,
array(
'prev_text' => __( 'Older comments' ),
'next_text' => __( 'Newer comments' ),
'screen_reader_text' => __( 'Comments navigation' ),
'aria_label' => __( 'Comments' ),
'class' => 'comment-navigation',
)
);
$prev_link = get_previous_comments_link( $args['prev_text'] );
$next_link = get_next_comments_link( $args['next_text'] );
if ( $prev_link ) {
$navigation .= '<div class="nav-previous">' . $prev_link . '</div>';
}
if ( $next_link ) {
$navigation .= '<div class="nav-next">' . $next_link . '</div>';
}
$navigation = _navigation_markup( $navigation, $args['class'], $args['screen_reader_text'], $args['aria_label'] );
}
return $navigation;
}
/**
* Displays navigation to next/previous set of comments, when applicable.
*
* @since 4.4.0
*
* @param array $args See get_the_comments_navigation() for available arguments. Default empty array.
*/
function the_comments_navigation( $args = array() ) {
echo get_the_comments_navigation( $args );
}
/**
* Retrieves a paginated navigation to next/previous set of comments, when applicable.
*
* @since 4.4.0
* @since 5.3.0 Added the `aria_label` parameter.
* @since 5.5.0 Added the `class` parameter.
*
* @see paginate_comments_links()
*
* @param array $args {
* Optional. Default pagination arguments.
*
* @type string $screen_reader_text Screen reader text for the nav element. Default 'Comments pagination'.
* @type string $aria_label ARIA label text for the nav element. Default 'Comments pagination'.
* @type string $class Custom class for the nav element. Default 'comments-pagination'.
* }
* @return string Markup for pagination links.
*/
function get_the_comments_pagination( $args = array() ) {
$navigation = '';
// Make sure the nav element has an aria-label attribute: fallback to the screen reader text.
if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) {
$args['aria_label'] = $args['screen_reader_text'];
}
$args = wp_parse_args(
$args,
array(
'screen_reader_text' => __( 'Comments pagination' ),
'aria_label' => __( 'Comments pagination' ),
'class' => 'comments-pagination',
)
);
$args['echo'] = false;
// Make sure we get a string back. Plain is the next best thing.
if ( isset( $args['type'] ) && 'array' === $args['type'] ) {
$args['type'] = 'plain';
}
$links = paginate_comments_links( $args );
if ( $links ) {
$navigation = _navigation_markup( $links, $args['class'], $args['screen_reader_text'], $args['aria_label'] );
}
return $navigation;
}
/**
* Displays a paginated navigation to next/previous set of comments, when applicable.
*
* @since 4.4.0
*
* @param array $args See get_the_comments_pagination() for available arguments. Default empty array.
*/
function the_comments_pagination( $args = array() ) {
echo get_the_comments_pagination( $args );
}
/**
* Retrieves the URL for the current site where the front end is accessible.
*
* Returns the 'home' option with the appropriate protocol. The protocol will be 'https'
* if is_ssl() evaluates to true; otherwise, it will be the same as the 'home' option.
* If `$scheme` is 'http' or 'https', is_ssl() is overridden.
*
* @since 3.0.0
*
* @param string $path Optional. Path relative to the home URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the home URL context. Accepts
* 'http', 'https', 'relative', 'rest', or null. Default null.
* @return string Home URL link with optional path appended.
*/
function home_url( $path = '', $scheme = null ) {
return get_home_url( null, $path, $scheme );
}
/**
* Retrieves the URL for a given site where the front end is accessible.
*
* Returns the 'home' option with the appropriate protocol. The protocol will be 'https'
* if is_ssl() evaluates to true; otherwise, it will be the same as the 'home' option.
* If `$scheme` is 'http' or 'https', is_ssl() is overridden.
*
* @since 3.0.0
*
* @param int|null $blog_id Optional. Site ID. Default null (current site).
* @param string $path Optional. Path relative to the home URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the home URL context. Accepts
* 'http', 'https', 'relative', 'rest', or null. Default null.
* @return string Home URL link with optional path appended.
*/
function get_home_url( $blog_id = null, $path = '', $scheme = null ) {
$orig_scheme = $scheme;
if ( empty( $blog_id ) || ! is_multisite() ) {
$url = get_option( 'home' );
} else {
switch_to_blog( $blog_id );
$url = get_option( 'home' );
restore_current_blog();
}
if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ), true ) ) {
if ( is_ssl() ) {
$scheme = 'https';
} else {
$scheme = parse_url( $url, PHP_URL_SCHEME );
}
}
$url = set_url_scheme( $url, $scheme );
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
/**
* Filters the home URL.
*
* @since 3.0.0
*
* @param string $url The complete home URL including scheme and path.
* @param string $path Path relative to the home URL. Blank string if no path is specified.
* @param string|null $orig_scheme Scheme to give the home URL context. Accepts 'http', 'https',
* 'relative', 'rest', or null.
* @param int|null $blog_id Site ID, or null for the current site.
*/
return apply_filters( 'home_url', $url, $path, $orig_scheme, $blog_id );
}
/**
* Retrieves the URL for the current site where WordPress application files
* (e.g. wp-blog-header.php or the wp-admin/ folder) are accessible.
*
* Returns the 'site_url' option with the appropriate protocol, 'https' if
* is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
* overridden.
*
* @since 3.0.0
*
* @param string $path Optional. Path relative to the site URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the site URL context. See set_url_scheme().
* @return string Site URL link with optional path appended.
*/
function site_url( $path = '', $scheme = null ) {
return get_site_url( null, $path, $scheme );
}
/**
* Retrieves the URL for a given site where WordPress application files
* (e.g. wp-blog-header.php or the wp-admin/ folder) are accessible.
*
* Returns the 'site_url' option with the appropriate protocol, 'https' if
* is_ssl() and 'http' otherwise. If `$scheme` is 'http' or 'https',
* `is_ssl()` is overridden.
*
* @since 3.0.0
*
* @param int|null $blog_id Optional. Site ID. Default null (current site).
* @param string $path Optional. Path relative to the site URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the site URL context. Accepts
* 'http', 'https', 'login', 'login_post', 'admin', or
* 'relative'. Default null.
* @return string Site URL link with optional path appended.
*/
function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
if ( empty( $blog_id ) || ! is_multisite() ) {
$url = get_option( 'siteurl' );
} else {
switch_to_blog( $blog_id );
$url = get_option( 'siteurl' );
restore_current_blog();
}
$url = set_url_scheme( $url, $scheme );
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
/**
* Filters the site URL.
*
* @since 2.7.0
*
* @param string $url The complete site URL including scheme and path.
* @param string $path Path relative to the site URL. Blank string if no path is specified.
* @param string|null $scheme Scheme to give the site URL context. Accepts 'http', 'https', 'login',
* 'login_post', 'admin', 'relative' or null.
* @param int|null $blog_id Site ID, or null for the current site.
*/
return apply_filters( 'site_url', $url, $path, $scheme, $blog_id );
}
/**
* Retrieves the URL to the admin area for the current site.
*
* @since 2.6.0
*
* @param string $path Optional. Path relative to the admin URL. Default empty.
* @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl().
* 'http' or 'https' can be passed to force those schemes.
* @return string Admin URL link with optional path appended.
*/
function admin_url( $path = '', $scheme = 'admin' ) {
return get_admin_url( null, $path, $scheme );
}
/**
* Retrieves the URL to the admin area for a given site.
*
* @since 3.0.0
*
* @param int|null $blog_id Optional. Site ID. Default null (current site).
* @param string $path Optional. Path relative to the admin URL. Default empty.
* @param string $scheme Optional. The scheme to use. Accepts 'http' or 'https',
* to force those schemes. Default 'admin', which obeys
* force_ssl_admin() and is_ssl().
* @return string Admin URL link with optional path appended.
*/
function get_admin_url( $blog_id = null, $path = '', $scheme = 'admin' ) {
$url = get_site_url( $blog_id, 'wp-admin/', $scheme );
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
/**
* Filters the admin area URL.
*
* @since 2.8.0
* @since 5.8.0 The `$scheme` parameter was added.
*
* @param string $url The complete admin area URL including scheme and path.
* @param string $path Path relative to the admin area URL. Blank string if no path is specified.
* @param int|null $blog_id Site ID, or null for the current site.
* @param string|null $scheme The scheme to use. Accepts 'http', 'https',
* 'admin', or null. Default 'admin', which obeys force_ssl_admin() and is_ssl().
*/
return apply_filters( 'admin_url', $url, $path, $blog_id, $scheme );
}
/**
* Retrieves the URL to the includes directory.
*
* @since 2.6.0
*
* @param string $path Optional. Path relative to the includes URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the includes URL context. Accepts
* 'http', 'https', or 'relative'. Default null.
* @return string Includes URL link with optional path appended.
*/
function includes_url( $path = '', $scheme = null ) {
$url = site_url( '/' . WPINC . '/', $scheme );
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
/**
* Filters the URL to the includes directory.
*
* @since 2.8.0
* @since 5.8.0 The `$scheme` parameter was added.
*
* @param string $url The complete URL to the includes directory including scheme and path.
* @param string $path Path relative to the URL to the wp-includes directory. Blank string
* if no path is specified.
* @param string|null $scheme Scheme to give the includes URL context. Accepts
* 'http', 'https', 'relative', or null. Default null.
*/
return apply_filters( 'includes_url', $url, $path, $scheme );
}
/**
* Retrieves the URL to the content directory.
*
* @since 2.6.0
*
* @param string $path Optional. Path relative to the content URL. Default empty.
* @return string Content URL link with optional path appended.
*/
function content_url( $path = '' ) {
$url = set_url_scheme( WP_CONTENT_URL );
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
/**
* Filters the URL to the content directory.
*
* @since 2.8.0
*
* @param string $url The complete URL to the content directory including scheme and path.
* @param string $path Path relative to the URL to the content directory. Blank string
* if no path is specified.
*/
return apply_filters( 'content_url', $url, $path );
}
/**
* Retrieves a URL within the plugins or mu-plugins directory.
*
* Defaults to the plugins directory URL if no arguments are supplied.
*
* @since 2.6.0
*
* @param string $path Optional. Extra path appended to the end of the URL, including
* the relative directory if $plugin is supplied. Default empty.
* @param string $plugin Optional. A full path to a file inside a plugin or mu-plugin.
* The URL will be relative to its directory. Default empty.
* Typically this is done by passing `__FILE__` as the argument.
* @return string Plugins URL link with optional paths appended.
*/
function plugins_url( $path = '', $plugin = '' ) {
$path = wp_normalize_path( $path );
$plugin = wp_normalize_path( $plugin );
$mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR );
if ( ! empty( $plugin ) && str_starts_with( $plugin, $mu_plugin_dir ) ) {
$url = WPMU_PLUGIN_URL;
} else {
$url = WP_PLUGIN_URL;
}
$url = set_url_scheme( $url );
if ( ! empty( $plugin ) && is_string( $plugin ) ) {
$folder = dirname( plugin_basename( $plugin ) );
if ( '.' !== $folder ) {
$url .= '/' . ltrim( $folder, '/' );
}
}
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
/**
* Filters the URL to the plugins directory.
*
* @since 2.8.0
*
* @param string $url The complete URL to the plugins directory including scheme and path.
* @param string $path Path relative to the URL to the plugins directory. Blank string
* if no path is specified.
* @param string $plugin The plugin file path to be relative to. Blank string if no plugin
* is specified.
*/
return apply_filters( 'plugins_url', $url, $path, $plugin );
}
/**
* Retrieves the site URL for the current network.
*
* Returns the site URL with the appropriate protocol, 'https' if
* is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
* overridden.
*
* @since 3.0.0
*
* @see set_url_scheme()
*
* @param string $path Optional. Path relative to the site URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the site URL context. Accepts
* 'http', 'https', or 'relative'. Default null.
* @return string Site URL link with optional path appended.
*/
function network_site_url( $path = '', $scheme = null ) {
if ( ! is_multisite() ) {
return site_url( $path, $scheme );
}
$current_network = get_network();
if ( 'relative' === $scheme ) {
$url = $current_network->path;
} else {
$url = set_url_scheme( 'http://' . $current_network->domain . $current_network->path, $scheme );
}
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
/**
* Filters the network site URL.
*
* @since 3.0.0
*
* @param string $url The complete network site URL including scheme and path.
* @param string $path Path relative to the network site URL. Blank string if
* no path is specified.
* @param string|null $scheme Scheme to give the URL context. Accepts 'http', 'https',
* 'relative' or null.
*/
return apply_filters( 'network_site_url', $url, $path, $scheme );
}
/**
* Retrieves the home URL for the current network.
*
* Returns the home URL with the appropriate protocol, 'https' is_ssl()
* and 'http' otherwise. If `$scheme` is 'http' or 'https', `is_ssl()` is
* overridden.
*
* @since 3.0.0
*
* @param string $path Optional. Path relative to the home URL. Default empty.
* @param string|null $scheme Optional. Scheme to give the home URL context. Accepts
* 'http', 'https', or 'relative'. Default null.
* @return string Home URL link with optional path appended.
*/
function network_home_url( $path = '', $scheme = null ) {
if ( ! is_multisite() ) {
return home_url( $path, $scheme );
}
$current_network = get_network();
$orig_scheme = $scheme;
if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ), true ) ) {
$scheme = is_ssl() ? 'https' : 'http';
}
if ( 'relative' === $scheme ) {
$url = $current_network->path;
} else {
$url = set_url_scheme( 'http://' . $current_network->domain . $current_network->path, $scheme );
}
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
/**
* Filters the network home URL.
*
* @since 3.0.0
*
* @param string $url The complete network home URL including scheme and path.
* @param string $path Path relative to the network home URL. Blank string
* if no path is specified.
* @param string|null $orig_scheme Scheme to give the URL context. Accepts 'http', 'https',
* 'relative' or null.
*/
return apply_filters( 'network_home_url', $url, $path, $orig_scheme );
}
/**
* Retrieves the URL to the admin area for the network.
*
* @since 3.0.0
*
* @param string $path Optional path relative to the admin URL. Default empty.
* @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin()
* and is_ssl(). 'http' or 'https' can be passed to force those schemes.
* @return string Admin URL link with optional path appended.
*/
function network_admin_url( $path = '', $scheme = 'admin' ) {
if ( ! is_multisite() ) {
return admin_url( $path, $scheme );
}
$url = network_site_url( 'wp-admin/network/', $scheme );
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
/**
* Filters the network admin URL.
*
* @since 3.0.0
* @since 5.8.0 The `$scheme` parameter was added.
*
* @param string $url The complete network admin URL including scheme and path.
* @param string $path Path relative to the network admin URL. Blank string if
* no path is specified.
* @param string|null $scheme The scheme to use. Accepts 'http', 'https',
* 'admin', or null. Default is 'admin', which obeys force_ssl_admin() and is_ssl().
*/
return apply_filters( 'network_admin_url', $url, $path, $scheme );
}
/**
* Retrieves the URL to the admin area for the current user.
*
* @since 3.0.0
*
* @param string $path Optional. Path relative to the admin URL. Default empty.
* @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin()
* and is_ssl(). 'http' or 'https' can be passed to force those schemes.
* @return string Admin URL link with optional path appended.
*/
function user_admin_url( $path = '', $scheme = 'admin' ) {
$url = network_site_url( 'wp-admin/user/', $scheme );
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
/**
* Filters the user admin URL for the current user.
*
* @since 3.1.0
* @since 5.8.0 The `$scheme` parameter was added.
*
* @param string $url The complete URL including scheme and path.
* @param string $path Path relative to the URL. Blank string if
* no path is specified.
* @param string|null $scheme The scheme to use. Accepts 'http', 'https',
* 'admin', or null. Default is 'admin', which obeys force_ssl_admin() and is_ssl().
*/
return apply_filters( 'user_admin_url', $url, $path, $scheme );
}
/**
* Retrieves the URL to the admin area for either the current site or the network depending on context.
*
* @since 3.1.0
*
* @param string $path Optional. Path relative to the admin URL. Default empty.
* @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin()
* and is_ssl(). 'http' or 'https' can be passed to force those schemes.
* @return string Admin URL link with optional path appended.
*/
function self_admin_url( $path = '', $scheme = 'admin' ) {
if ( is_network_admin() ) {
$url = network_admin_url( $path, $scheme );
} elseif ( is_user_admin() ) {
$url = user_admin_url( $path, $scheme );
} else {
$url = admin_url( $path, $scheme );
}
/**
* Filters the admin URL for the current site or network depending on context.
*
* @since 4.9.0
*
* @param string $url The complete URL including scheme and path.
* @param string $path Path relative to the URL. Blank string if no path is specified.
* @param string $scheme The scheme to use.
*/
return apply_filters( 'self_admin_url', $url, $path, $scheme );
}
/**
* Sets the scheme for a URL.
*
* @since 3.4.0
* @since 4.4.0 The 'rest' scheme was added.
*
* @param string $url Absolute URL that includes a scheme
* @param string|null $scheme Optional. Scheme to give $url. Currently 'http', 'https', 'login',
* 'login_post', 'admin', 'relative', 'rest', 'rpc', or null. Default null.
* @return string URL with chosen scheme.
*/
function set_url_scheme( $url, $scheme = null ) {
$orig_scheme = $scheme;
if ( ! $scheme ) {
$scheme = is_ssl() ? 'https' : 'http';
} elseif ( 'admin' === $scheme || 'login' === $scheme || 'login_post' === $scheme || 'rpc' === $scheme ) {
$scheme = is_ssl() || force_ssl_admin() ? 'https' : 'http';
} elseif ( 'http' !== $scheme && 'https' !== $scheme && 'relative' !== $scheme ) {
$scheme = is_ssl() ? 'https' : 'http';
}
$url = trim( $url );
if ( str_starts_with( $url, '//' ) ) {
$url = 'http:' . $url;
}
if ( 'relative' === $scheme ) {
$url = ltrim( preg_replace( '#^\w+://[^/]*#', '', $url ) );
if ( '' !== $url && '/' === $url[0] ) {
$url = '/' . ltrim( $url, "/ \t\n\r\0\x0B" );
}
} else {
$url = preg_replace( '#^\w+://#', $scheme . '://', $url );
}
/**
* Filters the resulting URL after setting the scheme.
*
* @since 3.4.0
*
* @param string $url The complete URL including scheme and path.
* @param string $scheme Scheme applied to the URL. One of 'http', 'https', or 'relative'.
* @param string|null $orig_scheme Scheme requested for the URL. One of 'http', 'https', 'login',
* 'login_post', 'admin', 'relative', 'rest', 'rpc', or null.
*/
return apply_filters( 'set_url_scheme', $url, $scheme, $orig_scheme );
}
/**
* Retrieves the URL to the user's dashboard.
*
* If a user does not belong to any site, the global user dashboard is used. If the user
* belongs to the current site, the dashboard for the current site is returned. If the user
* cannot edit the current site, the dashboard to the user's primary site is returned.
*
* @since 3.1.0
*
* @param int $user_id Optional. User ID. Defaults to current user.
* @param string $path Optional path relative to the dashboard. Use only paths known to
* both site and user admins. Default empty.
* @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin()
* and is_ssl(). 'http' or 'https' can be passed to force those schemes.
* @return string Dashboard URL link with optional path appended.
*/
function get_dashboard_url( $user_id = 0, $path = '', $scheme = 'admin' ) {
$user_id = $user_id ? (int) $user_id : get_current_user_id();
$blogs = get_blogs_of_user( $user_id );
if ( is_multisite() && ! user_can( $user_id, 'manage_network' ) && empty( $blogs ) ) {
$url = user_admin_url( $path, $scheme );
} elseif ( ! is_multisite() ) {
$url = admin_url( $path, $scheme );
} else {
$current_blog = get_current_blog_id();
if ( $current_blog && ( user_can( $user_id, 'manage_network' ) || in_array( $current_blog, array_keys( $blogs ), true ) ) ) {
$url = admin_url( $path, $scheme );
} else {
$active = get_active_blog_for_user( $user_id );
if ( $active ) {
$url = get_admin_url( $active->blog_id, $path, $scheme );
} else {
$url = user_admin_url( $path, $scheme );
}
}
}
/**
* Filters the dashboard URL for a user.
*
* @since 3.1.0
*
* @param string $url The complete URL including scheme and path.
* @param int $user_id The user ID.
* @param string $path Path relative to the URL. Blank string if no path is specified.
* @param string $scheme Scheme to give the URL context. Accepts 'http', 'https', 'login',
* 'login_post', 'admin', 'relative' or null.
*/
return apply_filters( 'user_dashboard_url', $url, $user_id, $path, $scheme );
}
/**
* Retrieves the URL to the user's profile editor.
*
* @since 3.1.0
*
* @param int $user_id Optional. User ID. Defaults to current user.
* @param string $scheme Optional. The scheme to use. Default is 'admin', which obeys force_ssl_admin()
* and is_ssl(). 'http' or 'https' can be passed to force those schemes.
* @return string Dashboard URL link with optional path appended.
*/
function get_edit_profile_url( $user_id = 0, $scheme = 'admin' ) {
$user_id = $user_id ? (int) $user_id : get_current_user_id();
if ( is_user_admin() ) {
$url = user_admin_url( 'profile.php', $scheme );
} elseif ( is_network_admin() ) {
$url = network_admin_url( 'profile.php', $scheme );
} else {
$url = get_dashboard_url( $user_id, 'profile.php', $scheme );
}
/**
* Filters the URL for a user's profile editor.
*
* @since 3.1.0
*
* @param string $url The complete URL including scheme and path.
* @param int $user_id The user ID.
* @param string $scheme Scheme to give the URL context. Accepts 'http', 'https', 'login',
* 'login_post', 'admin', 'relative' or null.
*/
return apply_filters( 'edit_profile_url', $url, $user_id, $scheme );
}
/**
* Returns the canonical URL for a post.
*
* When the post is the same as the current requested page the function will handle the
* pagination arguments too.
*
* @since 4.6.0
*
* @param int|WP_Post $post Optional. Post ID or object. Default is global `$post`.
* @return string|false The canonical URL. False if the post does not exist
* or has not been published yet.
*/
function wp_get_canonical_url( $post = null ) {
$post = get_post( $post );
if ( ! $post ) {
return false;
}
if ( 'publish' !== $post->post_status ) {
return false;
}
$canonical_url = get_permalink( $post );
// If a canonical is being generated for the current page, make sure it has pagination if needed.
if ( get_queried_object_id() === $post->ID ) {
$page = get_query_var( 'page', 0 );
if ( $page >= 2 ) {
if ( ! get_option( 'permalink_structure' ) ) {
$canonical_url = add_query_arg( 'page', $page, $canonical_url );
} else {
$canonical_url = trailingslashit( $canonical_url ) . user_trailingslashit( $page, 'single_paged' );
}
}
$cpage = get_query_var( 'cpage', 0 );
if ( $cpage ) {
$canonical_url = get_comments_pagenum_link( $cpage );
}
}
/**
* Filters the canonical URL for a post.
*
* @since 4.6.0
*
* @param string $canonical_url The post's canonical URL.
* @param WP_Post $post Post object.
*/
return apply_filters( 'get_canonical_url', $canonical_url, $post );
}
/**
* Outputs rel=canonical for singular queries.
*
* @since 2.9.0
* @since 4.6.0 Adjusted to use `wp_get_canonical_url()`.
*/
function rel_canonical() {
if ( ! is_singular() ) {
return;
}
$id = get_queried_object_id();
if ( 0 === $id ) {
return;
}
$url = wp_get_canonical_url( $id );
if ( ! empty( $url ) ) {
echo '<link rel="canonical" href="' . esc_url( $url ) . '" />' . "\n";
}
}
/**
* Returns a shortlink for a post, page, attachment, or site.
*
* This function exists to provide a shortlink tag that all themes and plugins can target.
* A plugin must hook in to provide the actual shortlinks. Default shortlink support is
* limited to providing ?p= style links for posts. Plugins can short-circuit this function
* via the {@see 'pre_get_shortlink'} filter or filter the output via the {@see 'get_shortlink'}
* filter.
*
* @since 3.0.0
*
* @param int $id Optional. A post or site ID. Default is 0, which means the current post or site.
* @param string $context Optional. Whether the ID is a 'site' ID, 'post' ID, or 'media' ID. If 'post',
* the post_type of the post is consulted. If 'query', the current query is consulted
* to determine the ID and context. Default 'post'.
* @param bool $allow_slugs Optional. Whether to allow post slugs in the shortlink. It is up to the plugin how
* and whether to honor this. Default true.
* @return string A shortlink or an empty string if no shortlink exists for the requested resource or if shortlinks
* are not enabled.
*/
function wp_get_shortlink( $id = 0, $context = 'post', $allow_slugs = true ) {
/**
* Filters whether to preempt generating a shortlink for the given post.
*
* Returning a value other than false from the filter will short-circuit
* the shortlink generation process, returning that value instead.
*
* @since 3.0.0
*
* @param false|string $return Short-circuit return value. Either false or a URL string.
* @param int $id Post ID, or 0 for the current post.
* @param string $context The context for the link. One of 'post' or 'query',
* @param bool $allow_slugs Whether to allow post slugs in the shortlink.
*/
$shortlink = apply_filters( 'pre_get_shortlink', false, $id, $context, $allow_slugs );
if ( false !== $shortlink ) {
return $shortlink;
}
$post_id = 0;
if ( 'query' === $context && is_singular() ) {
$post_id = get_queried_object_id();
$post = get_post( $post_id );
} elseif ( 'post' === $context ) {
$post = get_post( $id );
if ( ! empty( $post->ID ) ) {
$post_id = $post->ID;
}
}
$shortlink = '';
// Return `?p=` link for all public post types.
if ( ! empty( $post_id ) ) {
$post_type = get_post_type_object( $post->post_type );
if ( 'page' === $post->post_type
&& 'page' === get_option( 'show_on_front' ) && (int) get_option( 'page_on_front' ) === $post->ID
) {
$shortlink = home_url( '/' );
} elseif ( $post_type && $post_type->public ) {
$shortlink = home_url( '?p=' . $post_id );
}
}
/**
* Filters the shortlink for a post.
*
* @since 3.0.0
*
* @param string $shortlink Shortlink URL.
* @param int $id Post ID, or 0 for the current post.
* @param string $context The context for the link. One of 'post' or 'query',
* @param bool $allow_slugs Whether to allow post slugs in the shortlink. Not used by default.
*/
return apply_filters( 'get_shortlink', $shortlink, $id, $context, $allow_slugs );
}
/**
* Injects rel=shortlink into the head if a shortlink is defined for the current page.
*
* Attached to the {@see 'wp_head'} action.
*
* @since 3.0.0
*/
function wp_shortlink_wp_head() {
$shortlink = wp_get_shortlink( 0, 'query' );
if ( empty( $shortlink ) ) {
return;
}
echo "<link rel='shortlink' href='" . esc_url( $shortlink ) . "' />\n";
}
/**
* Sends a Link: rel=shortlink header if a shortlink is defined for the current page.
*
* Attached to the {@see 'wp'} action.
*
* @since 3.0.0
*/
function wp_shortlink_header() {
if ( headers_sent() ) {
return;
}
$shortlink = wp_get_shortlink( 0, 'query' );
if ( empty( $shortlink ) ) {
return;
}
header( 'Link: <' . $shortlink . '>; rel=shortlink', false );
}
/**
* Displays the shortlink for a post.
*
* Must be called from inside "The Loop"
*
* Call like the_shortlink( __( 'Shortlinkage FTW' ) )
*
* @since 3.0.0
* @since 6.8.0 Removed title attribute.
*
* @param string $text Optional. The link text or HTML to be displayed. Defaults to 'This is the short link.'
* @param string $title Unused.
* @param string $before Optional. HTML to display before the link. Default empty.
* @param string $after Optional. HTML to display after the link. Default empty.
*/
function the_shortlink( $text = '', $title = '', $before = '', $after = '' ) {
$post = get_post();
if ( empty( $text ) ) {
$text = __( 'This is the short link.' );
}
$shortlink = wp_get_shortlink( $post->ID );
if ( ! empty( $shortlink ) ) {
$link = '<a rel="shortlink" href="' . esc_url( $shortlink ) . '">' . $text . '</a>';
/**
* Filters the short link anchor tag for a post.
*
* @since 3.0.0
*
* @param string $link Shortlink anchor tag.
* @param string $shortlink Shortlink URL.
* @param string $text Shortlink's text.
* @param string $title Shortlink's title attribute. Unused.
*/
$link = apply_filters( 'the_shortlink', $link, $shortlink, $text, $title );
echo $before, $link, $after;
}
}
/**
* Retrieves the avatar URL.
*
* @since 4.2.0
*
* @param mixed $id_or_email The avatar to retrieve a URL for. Accepts a user ID, Gravatar SHA-256 or MD5 hash,
* user email, WP_User object, WP_Post object, or WP_Comment object.
* @param array $args {
* Optional. Arguments to use instead of the default arguments.
*
* @type int $size Height and width of the avatar in pixels. Default 96.
* @type string $default URL for the default image or a default type. Accepts:
* - '404' (return a 404 instead of a default image)
* - 'retro' (a 8-bit arcade-style pixelated face)
* - 'robohash' (a robot)
* - 'monsterid' (a monster)
* - 'wavatar' (a cartoon face)
* - 'identicon' (the "quilt", a geometric pattern)
* - 'mystery', 'mm', or 'mysteryman' (The Oyster Man)
* - 'blank' (transparent GIF)
* - 'gravatar_default' (the Gravatar logo)
* Default is the value of the 'avatar_default' option,
* with a fallback of 'mystery'.
* @type bool $force_default Whether to always show the default image, never the Gravatar.
* Default false.
* @type string $rating What rating to display avatars up to. Accepts:
* - 'G' (suitable for all audiences)
* - 'PG' (possibly offensive, usually for audiences 13 and above)
* - 'R' (intended for adult audiences above 17)
* - 'X' (even more mature than above)
* Default is the value of the 'avatar_rating' option.
* @type string $scheme URL scheme to use. See set_url_scheme() for accepted values.
* Default null.
* @type array $processed_args When the function returns, the value will be the processed/sanitized $args
* plus a "found_avatar" guess. Pass as a reference. Default null.
* }
* @return string|false The URL of the avatar on success, false on failure.
*/
function get_avatar_url( $id_or_email, $args = null ) {
$args = get_avatar_data( $id_or_email, $args );
return $args['url'];
}
/**
* Check if this comment type allows avatars to be retrieved.
*
* @since 5.1.0
*
* @param string $comment_type Comment type to check.
* @return bool Whether the comment type is allowed for retrieving avatars.
*/
function is_avatar_comment_type( $comment_type ) {
/**
* Filters the list of allowed comment types for retrieving avatars.
*
* @since 3.0.0
*
* @param array $types An array of content types. Default only contains 'comment'.
*/
$allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
return in_array( $comment_type, (array) $allowed_comment_types, true );
}
/**
* Retrieves default data about the avatar.
*
* @since 4.2.0
* @since 6.7.0 Gravatar URLs always use HTTPS.
* @since 6.8.0 Gravatar URLs use the SHA-256 hashing algorithm.
*
* @param mixed $id_or_email The avatar to retrieve. Accepts a user ID, Gravatar SHA-256 or MD5 hash,
* user email, WP_User object, WP_Post object, or WP_Comment object.
* @param array $args {
* Optional. Arguments to use instead of the default arguments.
*
* @type int $size Height and width of the avatar in pixels. Default 96.
* @type int $height Display height of the avatar in pixels. Defaults to $size.
* @type int $width Display width of the avatar in pixels. Defaults to $size.
* @type string $default URL for the default image or a default type. Accepts:
* - '404' (return a 404 instead of a default image)
* - 'retro' (a 8-bit arcade-style pixelated face)
* - 'robohash' (a robot)
* - 'monsterid' (a monster)
* - 'wavatar' (a cartoon face)
* - 'identicon' (the "quilt", a geometric pattern)
* - 'mystery', 'mm', or 'mysteryman' (The Oyster Man)
* - 'blank' (transparent GIF)
* - 'gravatar_default' (the Gravatar logo)
* Default is the value of the 'avatar_default' option,
* with a fallback of 'mystery'.
* @type bool $force_default Whether to always show the default image, never the Gravatar.
* Default false.
* @type string $rating What rating to display avatars up to. Accepts:
* - 'G' (suitable for all audiences)
* - 'PG' (possibly offensive, usually for audiences 13 and above)
* - 'R' (intended for adult audiences above 17)
* - 'X' (even more mature than above)
* Default is the value of the 'avatar_rating' option.
* @type string $scheme URL scheme to use. See set_url_scheme() for accepted values.
* For Gravatars this setting is ignored and HTTPS is used to avoid
* unnecessary redirects. The setting is retained for systems using
* the {@see 'pre_get_avatar_data'} filter to customize avatars.
* Default null.
* @type array $processed_args When the function returns, the value will be the processed/sanitized $args
* plus a "found_avatar" guess. Pass as a reference. Default null.
* @type string $extra_attr HTML attributes to insert in the IMG element. Is not sanitized.
* Default empty.
* }
* @return array {
* Along with the arguments passed in `$args`, this will contain a couple of extra arguments.
*
* @type bool $found_avatar True if an avatar was found for this user,
* false or not set if none was found.
* @type string|false $url The URL of the avatar that was found, or false.
* }
*/
function get_avatar_data( $id_or_email, $args = null ) {
$args = wp_parse_args(
$args,
array(
'size' => 96,
'height' => null,
'width' => null,
'default' => get_option( 'avatar_default', 'mystery' ),
'force_default' => false,
'rating' => get_option( 'avatar_rating' ),
'scheme' => null,
'processed_args' => null, // If used, should be a reference.
'extra_attr' => '',
)
);
if ( is_numeric( $args['size'] ) ) {
$args['size'] = absint( $args['size'] );
if ( ! $args['size'] ) {
$args['size'] = 96;
}
} else {
$args['size'] = 96;
}
if ( is_numeric( $args['height'] ) ) {
$args['height'] = absint( $args['height'] );
if ( ! $args['height'] ) {
$args['height'] = $args['size'];
}
} else {
$args['height'] = $args['size'];
}
if ( is_numeric( $args['width'] ) ) {
$args['width'] = absint( $args['width'] );
if ( ! $args['width'] ) {
$args['width'] = $args['size'];
}
} else {
$args['width'] = $args['size'];
}
if ( empty( $args['default'] ) ) {
$args['default'] = get_option( 'avatar_default', 'mystery' );
}
switch ( $args['default'] ) {
case 'mm':
case 'mystery':
case 'mysteryman':
$args['default'] = 'mm';
break;
case 'gravatar_default':
$args['default'] = false;
break;
}
$args['force_default'] = (bool) $args['force_default'];
$args['rating'] = strtolower( $args['rating'] );
$args['found_avatar'] = false;
/**
* Filters whether to retrieve the avatar URL early.
*
* Passing a non-null value in the 'url' member of the return array will
* effectively short circuit get_avatar_data(), passing the value through
* the {@see 'get_avatar_data'} filter and returning early.
*
* @since 4.2.0
*
* @param array $args Arguments passed to get_avatar_data(), after processing.
* @param mixed $id_or_email The avatar to retrieve. Accepts a user ID, Gravatar SHA-256 or MD5 hash,
* user email, WP_User object, WP_Post object, or WP_Comment object.
*/
$args = apply_filters( 'pre_get_avatar_data', $args, $id_or_email );
if ( isset( $args['url'] ) ) {
/** This filter is documented in wp-includes/link-template.php */
return apply_filters( 'get_avatar_data', $args, $id_or_email );
}
$email_hash = '';
$user = false;
$email = false;
if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
$id_or_email = get_comment( $id_or_email );
}
// Process the user identifier.
if ( is_numeric( $id_or_email ) ) {
$user = get_user_by( 'id', absint( $id_or_email ) );
} elseif ( is_string( $id_or_email ) ) {
if ( str_contains( $id_or_email, '@sha256.gravatar.com' ) ) {
// SHA-256 hash.
list( $email_hash ) = explode( '@', $id_or_email );
} elseif ( str_contains( $id_or_email, '@md5.gravatar.com' ) ) {
// MD5 hash.
list( $email_hash ) = explode( '@', $id_or_email );
} else {
// Email address.
$email = $id_or_email;
}
} elseif ( $id_or_email instanceof WP_User ) {
// User object.
$user = $id_or_email;
} elseif ( $id_or_email instanceof WP_Post ) {
// Post object.
$user = get_user_by( 'id', (int) $id_or_email->post_author );
} elseif ( $id_or_email instanceof WP_Comment ) {
if ( ! is_avatar_comment_type( get_comment_type( $id_or_email ) ) ) {
$args['url'] = false;
/** This filter is documented in wp-includes/link-template.php */
return apply_filters( 'get_avatar_data', $args, $id_or_email );
}
if ( ! empty( $id_or_email->user_id ) ) {
$user = get_user_by( 'id', (int) $id_or_email->user_id );
}
if ( ( ! $user || is_wp_error( $user ) ) && ! empty( $id_or_email->comment_author_email ) ) {
$email = $id_or_email->comment_author_email;
}
}
if ( ! $email_hash ) {
if ( $user ) {
$email = $user->user_email;
}
if ( $email ) {
$email_hash = hash( 'sha256', strtolower( trim( $email ) ) );
}
}
if ( $email_hash ) {
$args['found_avatar'] = true;
}
$url_args = array(
's' => $args['size'],
'd' => $args['default'],
'f' => $args['force_default'] ? 'y' : false,
'r' => $args['rating'],
);
/*
* Gravatars are always served over HTTPS.
*
* The Gravatar website redirects HTTP requests to HTTPS URLs so always
* use the HTTPS scheme to avoid unnecessary redirects.
*/
$url = 'https://secure.gravatar.com/avatar/' . $email_hash;
$url = add_query_arg(
rawurlencode_deep( array_filter( $url_args ) ),
$url
);
/**
* Filters the avatar URL.
*
* @since 4.2.0
*
* @param string $url The URL of the avatar.
* @param mixed $id_or_email The avatar to retrieve. Accepts a user ID, Gravatar SHA-256 or MD5 hash,
* user email, WP_User object, WP_Post object, or WP_Comment object.
* @param array $args Arguments passed to get_avatar_data(), after processing.
*/
$args['url'] = apply_filters( 'get_avatar_url', $url, $id_or_email, $args );
/**
* Filters the avatar data.
*
* @since 4.2.0
*
* @param array $args Arguments passed to get_avatar_data(), after processing.
* @param mixed $id_or_email The avatar to retrieve. Accepts a user ID, Gravatar SHA-256 or MD5 hash,
* user email, WP_User object, WP_Post object, or WP_Comment object.
*/
return apply_filters( 'get_avatar_data', $args, $id_or_email );
}
/**
* Retrieves the URL of a file in the theme.
*
* Searches in the stylesheet directory before the template directory so themes
* which inherit from a parent theme can just override one file.
*
* @since 4.7.0
*
* @param string $file Optional. File to search for in the stylesheet directory.
* @return string The URL of the file.
*/
function get_theme_file_uri( $file = '' ) {
$file = ltrim( $file, '/' );
$stylesheet_directory = get_stylesheet_directory();
if ( empty( $file ) ) {
$url = get_stylesheet_directory_uri();
} elseif ( get_template_directory() !== $stylesheet_directory && file_exists( $stylesheet_directory . '/' . $file ) ) {
$url = get_stylesheet_directory_uri() . '/' . $file;
} else {
$url = get_template_directory_uri() . '/' . $file;
}
/**
* Filters the URL to a file in the theme.
*
* @since 4.7.0
*
* @param string $url The file URL.
* @param string $file The requested file to search for.
*/
return apply_filters( 'theme_file_uri', $url, $file );
}
/**
* Retrieves the URL of a file in the parent theme.
*
* @since 4.7.0
*
* @param string $file Optional. File to return the URL for in the template directory.
* @return string The URL of the file.
*/
function get_parent_theme_file_uri( $file = '' ) {
$file = ltrim( $file, '/' );
if ( empty( $file ) ) {
$url = get_template_directory_uri();
} else {
$url = get_template_directory_uri() . '/' . $file;
}
/**
* Filters the URL to a file in the parent theme.
*
* @since 4.7.0
*
* @param string $url The file URL.
* @param string $file The requested file to search for.
*/
return apply_filters( 'parent_theme_file_uri', $url, $file );
}
/**
* Retrieves the path of a file in the theme.
*
* Searches in the stylesheet directory before the template directory so themes
* which inherit from a parent theme can just override one file.
*
* @since 4.7.0
*
* @param string $file Optional. File to search for in the stylesheet directory.
* @return string The path of the file.
*/
function get_theme_file_path( $file = '' ) {
$file = ltrim( $file, '/' );
$stylesheet_directory = get_stylesheet_directory();
$template_directory = get_template_directory();
if ( empty( $file ) ) {
$path = $stylesheet_directory;
} elseif ( $stylesheet_directory !== $template_directory && file_exists( $stylesheet_directory . '/' . $file ) ) {
$path = $stylesheet_directory . '/' . $file;
} else {
$path = $template_directory . '/' . $file;
}
/**
* Filters the path to a file in the theme.
*
* @since 4.7.0
*
* @param string $path The file path.
* @param string $file The requested file to search for.
*/
return apply_filters( 'theme_file_path', $path, $file );
}
/**
* Retrieves the path of a file in the parent theme.
*
* @since 4.7.0
*
* @param string $file Optional. File to return the path for in the template directory.
* @return string The path of the file.
*/
function get_parent_theme_file_path( $file = '' ) {
$file = ltrim( $file, '/' );
if ( empty( $file ) ) {
$path = get_template_directory();
} else {
$path = get_template_directory() . '/' . $file;
}
/**
* Filters the path to a file in the parent theme.
*
* @since 4.7.0
*
* @param string $path The file path.
* @param string $file The requested file to search for.
*/
return apply_filters( 'parent_theme_file_path', $path, $file );
}
/**
* Retrieves the URL to the privacy policy page.
*
* @since 4.9.6
*
* @return string The URL to the privacy policy page. Empty string if it doesn't exist.
*/
function get_privacy_policy_url() {
$url = '';
$policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' );
if ( ! empty( $policy_page_id ) && get_post_status( $policy_page_id ) === 'publish' ) {
$url = (string) get_permalink( $policy_page_id );
}
/**
* Filters the URL of the privacy policy page.
*
* @since 4.9.6
*
* @param string $url The URL to the privacy policy page. Empty string
* if it doesn't exist.
* @param int $policy_page_id The ID of privacy policy page.
*/
return apply_filters( 'privacy_policy_url', $url, $policy_page_id );
}
/**
* Displays the privacy policy link with formatting, when applicable.
*
* @since 4.9.6
*
* @param string $before Optional. Display before privacy policy link. Default empty.
* @param string $after Optional. Display after privacy policy link. Default empty.
*/
function the_privacy_policy_link( $before = '', $after = '' ) {
echo get_the_privacy_policy_link( $before, $after );
}
/**
* Returns the privacy policy link with formatting, when applicable.
*
* @since 4.9.6
* @since 6.2.0 Added 'privacy-policy' rel attribute.
*
* @param string $before Optional. Display before privacy policy link. Default empty.
* @param string $after Optional. Display after privacy policy link. Default empty.
* @return string Markup for the link and surrounding elements. Empty string if it
* doesn't exist.
*/
function get_the_privacy_policy_link( $before = '', $after = '' ) {
$link = '';
$privacy_policy_url = get_privacy_policy_url();
$policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' );
$page_title = ( $policy_page_id ) ? get_the_title( $policy_page_id ) : '';
if ( $privacy_policy_url && $page_title ) {
$link = sprintf(
'<a class="privacy-policy-link" href="%s" rel="privacy-policy">%s</a>',
esc_url( $privacy_policy_url ),
esc_html( $page_title )
);
}
/**
* Filters the privacy policy link.
*
* @since 4.9.6
*
* @param string $link The privacy policy link. Empty string if it
* doesn't exist.
* @param string $privacy_policy_url The URL of the privacy policy. Empty string
* if it doesn't exist.
*/
$link = apply_filters( 'the_privacy_policy_link', $link, $privacy_policy_url );
if ( $link ) {
return $before . $link . $after;
}
return '';
}
/**
* Returns an array of URL hosts which are considered to be internal hosts.
*
* By default the list of internal hosts is comprised of the host name of
* the site's home_url() (as parsed by wp_parse_url()).
*
* This list is used when determining if a specified URL is a link to a page on
* the site itself or a link offsite (to an external host). This is used, for
* example, when determining if the "nofollow" attribute should be applied to a
* link.
*
* @see wp_is_internal_link
*
* @since 6.2.0
*
* @return string[] An array of URL hosts.
*/
function wp_internal_hosts() {
static $internal_hosts;
if ( empty( $internal_hosts ) ) {
/**
* Filters the array of URL hosts which are considered internal.
*
* @since 6.2.0
*
* @param string[] $internal_hosts An array of internal URL hostnames.
*/
$internal_hosts = apply_filters(
'wp_internal_hosts',
array(
wp_parse_url( home_url(), PHP_URL_HOST ),
)
);
$internal_hosts = array_unique(
array_map( 'strtolower', (array) $internal_hosts )
);
}
return $internal_hosts;
}
/**
* Determines whether or not the specified URL is of a host included in the internal hosts list.
*
* @see wp_internal_hosts()
*
* @since 6.2.0
*
* @param string $link The URL to test.
* @return bool Returns true for internal URLs and false for all other URLs.
*/
function wp_is_internal_link( $link ) {
$link = strtolower( $link );
if ( in_array( wp_parse_url( $link, PHP_URL_SCHEME ), wp_allowed_protocols(), true ) ) {
return in_array( wp_parse_url( $link, PHP_URL_HOST ), wp_internal_hosts(), true );
}
return false;
}
##
## Bundle of CA Root Certificates
##
## WordPress Modification - We prepend some unexpired 'legacy' 1024bit certificates
## for backward compatibility. See https://core.trac.wordpress.org/ticket/34935#comment:10
##
Verisign Class 3 Public Primary Certification Authority
=======================================================
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA
TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah
WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf
Tqj/ZA1k
-----END CERTIFICATE-----
Verisign Class 3 Public Primary Certification Authority - G2
============================================================
-----BEGIN CERTIFICATE-----
MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO
FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71
lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB
MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT
1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD
Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
-----END CERTIFICATE-----
Verisign Class 3 Public Primary Certification Authority
=======================================================
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx
FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow
XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky
CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX
bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/
D/xwzoiQ
-----END CERTIFICATE-----
##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Tue Feb 25 04:12:03 2025 GMT
##
## Find updated versions here: https://curl.se/docs/caextract.html
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt). This file can be found in the mozilla source tree:
## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
## an Apache+mod_ssl webserver for SSL client authentication.
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.29.
## SHA256: 620fd89c02acb0019f1899dab7907db5d20735904f5a9a0d3a8771a5857ac482
##
GlobalSign Root CA
==================
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----
Entrust.net Premium 2048 Secure Server CA
=========================================
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----
Baltimore CyberTrust Root
=========================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----
Comodo AAA Services root
========================
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
QuoVadis Root CA 2
==================
-----BEGIN CERTIFICATE-----
MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
-----END CERTIFICATE-----
QuoVadis Root CA 3
==================
-----BEGIN CERTIFICATE-----
MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
-----END CERTIFICATE-----
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
-----END CERTIFICATE-----
Go Daddy Class 2 CA
===================
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
vZ8=
-----END CERTIFICATE-----
Starfield Class 2 CA
====================
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
QBFGmh95DmK/D5fs4C8fF5Q=
-----END CERTIFICATE-----
DigiCert Assured ID Root CA
===========================
-----BEGIN CERTIFICATE-----
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
-----END CERTIFICATE-----
DigiCert Global Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
DigiCert High Assurance EV Root CA
==================================
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
-----END CERTIFICATE-----
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
-----END CERTIFICATE-----
SecureTrust CA
==============
-----BEGIN CERTIFICATE-----
MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
-----END CERTIFICATE-----
Secure Global CA
================
-----BEGIN CERTIFICATE-----
MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
-----END CERTIFICATE-----
COMODO Certification Authority
==============================
-----BEGIN CERTIFICATE-----
MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
-----END CERTIFICATE-----
COMODO ECC Certification Authority
==================================
-----BEGIN CERTIFICATE-----
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----
Certigna
========
-----BEGIN CERTIFICATE-----
MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----
ePKI Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
-----END CERTIFICATE-----
certSIGN ROOT CA
================
-----BEGIN CERTIFICATE-----
MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
-----END CERTIFICATE-----
NetLock Arany (Class Gold) Főtanúsítvány
========================================
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----
Microsec e-Szigno Root CA 2009
==============================
-----BEGIN CERTIFICATE-----
MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
LXpUq3DDfSJlgnCW
-----END CERTIFICATE-----
GlobalSign Root CA - R3
=======================
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
kpeDMdmztcpHWD9f
-----END CERTIFICATE-----
Izenpe.com
==========
-----BEGIN CERTIFICATE-----
MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
-----END CERTIFICATE-----
Go Daddy Root Certificate Authority - G2
========================================
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
-----END CERTIFICATE-----
Starfield Root Certificate Authority - G2
=========================================
-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
-----END CERTIFICATE-----
Starfield Services Root Certificate Authority - G2
==================================================
-----BEGIN CERTIFICATE-----
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
-----END CERTIFICATE-----
AffirmTrust Commercial
======================
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
-----END CERTIFICATE-----
AffirmTrust Networking
======================
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
-----END CERTIFICATE-----
AffirmTrust Premium
===================
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
-----END CERTIFICATE-----
AffirmTrust Premium ECC
=======================
-----BEGIN CERTIFICATE-----
MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
eQ==
-----END CERTIFICATE-----
Certum Trusted Network CA
=========================
-----BEGIN CERTIFICATE-----
MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
-----END CERTIFICATE-----
TWCA Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
-----END CERTIFICATE-----
Security Communication RootCA2
==============================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----
Actalis Authentication Root CA
==============================
-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
-----END CERTIFICATE-----
Buypass Class 2 Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
rJgWVqA=
-----END CERTIFICATE-----
Buypass Class 3 Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
Cp/HuZc=
-----END CERTIFICATE-----
T-TeleSec GlobalRoot Class 3
============================
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
-----END CERTIFICATE-----
D-TRUST Root Class 3 CA 2 2009
==============================
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
-----END CERTIFICATE-----
D-TRUST Root Class 3 CA 2 EV 2009
=================================
-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
w9y4AyHqnxbxLFS1
-----END CERTIFICATE-----
CA Disig Root R2
================
-----BEGIN CERTIFICATE-----
MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
7+ZtsH8tZ/3zbBt1RqPlShfppNcL
-----END CERTIFICATE-----
ACCVRAIZ1
=========
-----BEGIN CERTIFICATE-----
MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
EfbRD0tVNEYqi4Y7
-----END CERTIFICATE-----
TWCA Global Root CA
===================
-----BEGIN CERTIFICATE-----
MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
-----END CERTIFICATE-----
TeliaSonera Root CA v1
======================
-----BEGIN CERTIFICATE-----
MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
-----END CERTIFICATE-----
T-TeleSec GlobalRoot Class 2
============================
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
-----END CERTIFICATE-----
Atos TrustedRoot 2011
=====================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----
QuoVadis Root CA 1 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
hMJKzRwuJIczYOXD
-----END CERTIFICATE-----
QuoVadis Root CA 2 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
O3jtZsSOeWmD3n+M
-----END CERTIFICATE-----
QuoVadis Root CA 3 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
PpxxVJkES/1Y+Zj0
-----END CERTIFICATE-----
DigiCert Assured ID Root G2
===========================
-----BEGIN CERTIFICATE-----
MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
IhNzbM8m9Yop5w==
-----END CERTIFICATE-----
DigiCert Assured ID Root G3
===========================
-----BEGIN CERTIFICATE-----
MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
1vUhZscv6pZjamVFkpUBtA==
-----END CERTIFICATE-----
DigiCert Global Root G2
=======================
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----
DigiCert Global Root G3
=======================
-----BEGIN CERTIFICATE-----
MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
VOKa5Vt8sycX
-----END CERTIFICATE-----
DigiCert Trusted Root G4
========================
-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
82Z+
-----END CERTIFICATE-----
COMODO RSA Certification Authority
==================================
-----BEGIN CERTIFICATE-----
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
LaZRfyHBNVOFBkpdn627G190
-----END CERTIFICATE-----
USERTrust RSA Certification Authority
=====================================
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----
USERTrust ECC Certification Authority
=====================================
-----BEGIN CERTIFICATE-----
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
-----END CERTIFICATE-----
GlobalSign ECC Root CA - R5
===========================
-----BEGIN CERTIFICATE-----
MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
-----END CERTIFICATE-----
IdenTrust Commercial Root CA 1
==============================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
cGzM7vRX+Bi6hG6H
-----END CERTIFICATE-----
IdenTrust Public Sector Root CA 1
=================================
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
3Wl9af0AVqW3rLatt8o+Ae+c
-----END CERTIFICATE-----
Entrust Root Certification Authority - G2
=========================================
-----BEGIN CERTIFICATE-----
MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
e4pIb4tF9g==
-----END CERTIFICATE-----
Entrust Root Certification Authority - EC1
==========================================
-----BEGIN CERTIFICATE-----
MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
-----END CERTIFICATE-----
CFCA EV ROOT
============
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
-----END CERTIFICATE-----
OISTE WISeKey Global Root GB CA
===============================
-----BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
-----END CERTIFICATE-----
SZAFIR ROOT CA2
===============
-----BEGIN CERTIFICATE-----
MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
-----END CERTIFICATE-----
Certum Trusted Network CA 2
===========================
-----BEGIN CERTIFICATE-----
MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
zAYspsbiDrW5viSP
-----END CERTIFICATE-----
Hellenic Academic and Research Institutions RootCA 2015
=======================================================
-----BEGIN CERTIFICATE-----
MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
p/UsQu0yrbYhnr68
-----END CERTIFICATE-----
Hellenic Academic and Research Institutions ECC RootCA 2015
===========================================================
-----BEGIN CERTIFICATE-----
MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
-----END CERTIFICATE-----
ISRG Root X1
============
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
AC RAIZ FNMT-RCM
================
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
-----END CERTIFICATE-----
Amazon Root CA 1
================
-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----
Amazon Root CA 2
================
-----BEGIN CERTIFICATE-----
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
-----END CERTIFICATE-----
Amazon Root CA 3
================
-----BEGIN CERTIFICATE-----
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
-----END CERTIFICATE-----
Amazon Root CA 4
================
-----BEGIN CERTIFICATE-----
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
-----END CERTIFICATE-----
TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
=============================================
-----BEGIN CERTIFICATE-----
MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
-----END CERTIFICATE-----
GDCA TrustAUTH R5 ROOT
======================
-----BEGIN CERTIFICATE-----
MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw
BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD
DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow
YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs
AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p
OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr
pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ
9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ
xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM
R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ
D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4
oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx
9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9
H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35
6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd
+PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ
HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD
F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ
8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv
/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT
aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
-----END CERTIFICATE-----
SSL.com Root Certification Authority RSA
========================================
-----BEGIN CERTIFICATE-----
MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM
BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x
MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw
MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM
LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C
Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8
P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge
oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp
k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z
fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ
gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2
UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8
1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s
bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr
dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf
ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl
u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq
erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj
MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ
vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI
Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y
wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI
WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=
-----END CERTIFICATE-----
SSL.com Root Certification Authority ECC
========================================
-----BEGIN CERTIFICATE-----
MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV
BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv
BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy
MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+
8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR
hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT
jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW
e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z
5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
-----END CERTIFICATE-----
SSL.com EV Root Certification Authority RSA R2
==============================================
-----BEGIN CERTIFICATE-----
MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w
DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u
MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD
VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh
hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w
cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO
Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+
B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh
CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim
9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto
RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm
JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48
+qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp
qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1
++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx
Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G
guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz
OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7
CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq
lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR
rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1
hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX
9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
-----END CERTIFICATE-----
SSL.com EV Root Certification Authority ECC
===========================================
-----BEGIN CERTIFICATE-----
MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV
BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy
BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw
MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM
LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy
3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O
BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe
5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ
N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm
m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
-----END CERTIFICATE-----
GlobalSign Root CA - R6
=======================
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX
R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i
YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss
grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE
3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF
vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM
PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+
azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O
WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy
CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP
0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN
b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV
HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0
lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY
BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym
Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr
3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1
0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T
uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK
oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t
JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
-----END CERTIFICATE-----
OISTE WISeKey Global Root GC CA
===============================
-----BEGIN CERTIFICATE-----
MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD
SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo
MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa
Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL
ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr
VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab
NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E
AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk
AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
-----END CERTIFICATE-----
UCA Global G2 Root
==================
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG
EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x
NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU
cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT
oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV
8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS
h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o
LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/
R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe
KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa
4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc
OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97
8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo
5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A
Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9
yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX
c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo
jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk
bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x
ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn
RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==
-----END CERTIFICATE-----
UCA Extended Validation Root
============================
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG
EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u
IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G
A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs
iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF
Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu
eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR
59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH
0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR
el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv
B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth
WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS
NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS
3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL
BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM
aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4
dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb
+7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW
F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi
GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc
GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi
djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr
dhh2n1ax
-----END CERTIFICATE-----
Certigna Root CA
================
-----BEGIN CERTIFICATE-----
MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE
BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ
MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda
MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz
MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX
stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz
KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8
JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16
XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq
4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej
wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ
lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI
jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/
/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy
dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h
LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl
cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt
OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP
TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq
7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3
4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd
8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS
6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY
tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS
aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde
E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
-----END CERTIFICATE-----
emSign Root CA - G1
===================
-----BEGIN CERTIFICATE-----
MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET
MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx
ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk
aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN
LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1
cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW
DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ
6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH
hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2
vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q
NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q
+Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih
U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
iN66zB+Afko=
-----END CERTIFICATE-----
emSign ECC Root CA - G3
=======================
-----BEGIN CERTIFICATE-----
MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG
A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4
MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11
ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc
58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr
MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D
CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7
jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj
-----END CERTIFICATE-----
emSign Root CA - C1
===================
-----BEGIN CERTIFICATE-----
MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx
EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp
Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE
BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD
ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up
ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/
Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX
OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V
I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms
lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+
XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp
/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1
NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9
wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ
BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
-----END CERTIFICATE-----
emSign ECC Root CA - C3
=======================
-----BEGIN CERTIFICATE-----
MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG
A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF
Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE
BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD
ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd
6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9
SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA
B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA
MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU
ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
-----END CERTIFICATE-----
Hongkong Post Root CA 3
=======================
-----BEGIN CERTIFICATE-----
MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG
A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK
Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2
MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv
bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX
SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz
iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf
jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim
5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe
sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj
0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/
JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u
y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h
+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG
xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID
AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN
AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw
W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld
y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov
+BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc
eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw
9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7
nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY
hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB
60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq
dBb9HxEGmpv0
-----END CERTIFICATE-----
Microsoft ECC Root Certificate Authority 2017
=============================================
-----BEGIN CERTIFICATE-----
MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND
IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4
MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ
BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6
thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB
eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM
+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf
Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR
eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
-----END CERTIFICATE-----
Microsoft RSA Root Certificate Authority 2017
=============================================
-----BEGIN CERTIFICATE-----
MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG
EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg
UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw
NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw
ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml
7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e
S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7
1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+
dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F
yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS
MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr
lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ
0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ
ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og
6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80
dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk
+ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex
/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy
AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW
ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE
7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT
c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D
5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E
-----END CERTIFICATE-----
e-Szigno Root CA 2017
=====================
-----BEGIN CERTIFICATE-----
MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw
DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt
MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa
Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE
CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp
Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx
s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G
A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv
vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA
tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO
svxyqltZ+efcMQ==
-----END CERTIFICATE-----
certSIGN Root CA G2
===================
-----BEGIN CERTIFICATE-----
MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw
EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy
MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH
TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05
N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk
abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg
wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp
dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh
ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732
jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf
95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc
z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL
iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB
ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB
/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5
8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5
BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW
atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU
Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M
NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N
0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=
-----END CERTIFICATE-----
Trustwave Global Certification Authority
========================================
-----BEGIN CERTIFICATE-----
MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV
UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u
IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV
UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u
IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29
zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf
LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq
stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o
WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+
OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40
Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE
uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm
+9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj
ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB
BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H
PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H
ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla
4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R
vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd
zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O
856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH
Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu
3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP
29FpHOTKyeC2nOnOcXHebD8WpHk=
-----END CERTIFICATE-----
Trustwave Global ECC P256 Certification Authority
=================================================
-----BEGIN CERTIFICATE-----
MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER
MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp
Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy
dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1
NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj
43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm
P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt
0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz
RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
-----END CERTIFICATE-----
Trustwave Global ECC P384 Certification Authority
=================================================
-----BEGIN CERTIFICATE-----
MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER
MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp
Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy
dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4
NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH
Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr
/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV
HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn
ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl
CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw==
-----END CERTIFICATE-----
NAVER Global Root Certification Authority
=========================================
-----BEGIN CERTIFICATE-----
MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG
A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD
DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4
NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT
UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb
UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW
+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7
XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2
aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4
Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z
VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B
A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai
cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy
YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV
HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK
21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB
jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx
hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg
E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH
D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ
A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY
qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG
I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg
kpzNNIaRkPpkUZ3+/uul9XXeifdy
-----END CERTIFICATE-----
AC RAIZ FNMT-RCM SERVIDORES SEGUROS
===================================
-----BEGIN CERTIFICATE-----
MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF
UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy
NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4
MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt
UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB
QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2
LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG
SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD
zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c=
-----END CERTIFICATE-----
GlobalSign Root R46
===================
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv
b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX
BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es
CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/
r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje
2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt
bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj
K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4
12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on
ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls
eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9
vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM
BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy
gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92
CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm
OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq
JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye
qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz
nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7
DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3
QEUxeCp6
-----END CERTIFICATE-----
GlobalSign Root E46
===================
-----BEGIN CERTIFICATE-----
MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT
AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg
RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV
BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq
hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB
jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj
QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL
gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk
vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+
CAezNIm8BZ/3Hobui3A=
-----END CERTIFICATE-----
GLOBALTRUST 2020
================
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx
IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT
VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh
BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy
MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi
D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO
VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM
CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm
fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA
A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR
JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG
DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU
clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ
mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud
IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA
VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw
4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9
iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS
8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2
HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS
vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918
oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF
YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl
gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
-----END CERTIFICATE-----
ANF Secure Server Root CA
=========================
-----BEGIN CERTIFICATE-----
MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4
NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv
bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg
Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw
MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw
EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz
BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv
T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv
B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse
zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM
VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j
7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z
JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe
8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO
Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E
BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ
UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx
j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt
dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM
5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb
5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54
EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H
hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy
g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3
r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
-----END CERTIFICATE-----
Certum EC-384 CA
================
-----BEGIN CERTIFICATE-----
MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ
TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2
MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh
dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq
vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn
iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo
ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0
QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
-----END CERTIFICATE-----
Certum Trusted Root CA
======================
-----BEGIN CERTIFICATE-----
MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG
EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew
HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY
QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p
fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52
HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2
fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt
g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4
NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk
fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ
P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY
njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK
HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL
LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s
ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K
h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8
CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA
4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo
WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj
6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT
OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck
bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
-----END CERTIFICATE-----
TunTrust Root CA
================
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG
A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj
dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw
NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD
ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz
2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b
bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7
NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd
gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW
VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f
Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ
juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas
DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS
VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI
04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl
0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd
Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY
YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp
adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x
xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP
jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM
MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z
ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r
AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
-----END CERTIFICATE-----
HARICA TLS RSA Root CA 2021
===========================
-----BEGIN CERTIFICATE-----
MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG
EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz
OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl
bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB
IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN
JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu
a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y
Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K
5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv
dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR
0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH
GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm
haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ
CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU
EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq
QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD
QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR
j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5
vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0
qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6
Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/
PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn
kf3/W9b3raYvAwtt41dU63ZTGI0RmLo=
-----END CERTIFICATE-----
HARICA TLS ECC Root CA 2021
===========================
-----BEGIN CERTIFICATE-----
MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH
UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD
QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX
DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj
IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv
b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l
AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b
ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW
0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi
rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw
CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
-----END CERTIFICATE-----
Autoridad de Certificacion Firmaprofesional CIF A62634068
=========================================================
-----BEGIN CERTIFICATE-----
MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA
BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw
QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud
DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w
gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j
b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A
bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC
AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL
4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb
LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il
I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP
cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA
LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A
lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH
9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf
NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE
ZycPvEJdvSRUDewdcAZfpLz6IHxV
-----END CERTIFICATE-----
vTrus ECC Root CA
=================
-----BEGIN CERTIFICATE-----
MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE
BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS
b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa
BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c
ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n
TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO
BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT
QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL
YgmRWAD5Tfs0aNoJrSEGGJTO
-----END CERTIFICATE-----
vTrus Root CA
=============
-----BEGIN CERTIFICATE-----
MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG
A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv
b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG
A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots
SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI
ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF
XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA
YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70
kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2
AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu
/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu
1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO
9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg
scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC
AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd
nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr
jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4
8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn
xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg
icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4
sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW
nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc
SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H
l3s=
-----END CERTIFICATE-----
ISRG Root X2
============
-----BEGIN CERTIFICATE-----
MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV
UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT
UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT
MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS
RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H
ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb
d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF
cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5
U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn
-----END CERTIFICATE-----
HiPKI Root CA - G1
==================
-----BEGIN CERTIFICATE-----
MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG
EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ
IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT
AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg
Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0
o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k
wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE
YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA
GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd
hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj
1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4
9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/
Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF
8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi
7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl
tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE
wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q
JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv
5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz
jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg
hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb
yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/
yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==
-----END CERTIFICATE-----
GlobalSign ECC Root CA - R4
===========================
-----BEGIN CERTIFICATE-----
MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i
YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i
YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW
ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E
BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI
KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg
UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
-----END CERTIFICATE-----
GTS Root R1
===========
-----BEGIN CERTIFICATE-----
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV
UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0
xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w
B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW
nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk
9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq
kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A
K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX
V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW
cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD
ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi
ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar
J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci
NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me
LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF
fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+
7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3
FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3
gm3c
-----END CERTIFICATE-----
GTS Root R2
===========
-----BEGIN CERTIFICATE-----
MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV
UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl
e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb
a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS
+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M
kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG
r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q
S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV
J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL
dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD
ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8
0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh
swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel
/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn
jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5
9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M
7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8
0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR
WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW
HYbL
-----END CERTIFICATE-----
GTS Root R3
===========
-----BEGIN CERTIFICATE-----
MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi
MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw
HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ
R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO
PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA
MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq
Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT
L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV
11RZt+cRLInUue4X
-----END CERTIFICATE-----
GTS Root R4
===========
-----BEGIN CERTIFICATE-----
MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi
MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw
HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ
R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO
PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA
MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1
PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C
r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh
4rsUecrNIdSUtUlD
-----END CERTIFICATE-----
Telia Root CA v2
================
-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT
AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2
MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK
DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI
hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7
6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q
9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn
pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl
tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW
5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr
RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E
BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4
M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau
BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W
xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD
VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5
tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H
eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C
y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC
QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15
h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70
sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9
xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ
raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc=
-----END CERTIFICATE-----
D-TRUST BR Root CA 1 2020
=========================
-----BEGIN CERTIFICATE-----
MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy
MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7
dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu
QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t
MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom
AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87
-----END CERTIFICATE-----
D-TRUST EV Root CA 1 2020
=========================
-----BEGIN CERTIFICATE-----
MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy
MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8
ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ
raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL
MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR
AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW
-----END CERTIFICATE-----
DigiCert TLS ECC P384 Root G5
=============================
-----BEGIN CERTIFICATE-----
MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4
NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx
FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg
Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd
lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj
n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB
/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds
Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx
AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA==
-----END CERTIFICATE-----
DigiCert TLS RSA4096 Root G5
============================
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG
EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0
MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2
IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8
7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU
AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces
tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa
zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV
DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q
TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy
z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/
MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk
wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E
FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w
DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN
lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN
MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/
u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G
OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh
47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU
FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ
yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP
bEtoL8pU9ozaMv7Da4M/OMZ+
-----END CERTIFICATE-----
Certainly Root R1
=================
-----BEGIN CERTIFICATE-----
MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN
MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy
dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O
5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl
8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl
DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI
XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN
KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ
AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb
rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1
VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS
p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz
HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v
MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB
GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+
gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH
JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7
fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw
x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S
X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8=
-----END CERTIFICATE-----
Certainly Root E1
=================
-----BEGIN CERTIFICATE-----
MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV
UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0
MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu
bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4
fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9
YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E
AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8
rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
-----END CERTIFICATE-----
Security Communication ECC RootCA1
==================================
-----BEGIN CERTIFICATE-----
MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD
VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t
dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL
MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV
BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo
5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW
BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK
BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L
snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e
N9k=
-----END CERTIFICATE-----
BJCA Global Root CA1
====================
-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG
EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK
Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG
A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD
DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm
CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS
sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn
P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW
yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj
eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn
MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b
OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh
GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK
H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB
AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G
A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4
YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ
dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8
60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh
TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW
4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp
GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx
4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps
3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S
SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI=
-----END CERTIFICATE-----
BJCA Global Root CA2
====================
-----BEGIN CERTIFICATE-----
MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD
TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg
R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE
BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC
SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl
SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK
/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI
1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8
W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g
UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
-----END CERTIFICATE-----
Sectigo Public Server Authentication Root E46
=============================================
-----BEGIN CERTIFICATE-----
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH
QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2
ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5
WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0
aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr
gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0
NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud
DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH
lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U
SAGKcw==
-----END CERTIFICATE-----
Sectigo Public Server Authentication Root R46
=============================================
-----BEGIN CERTIFICATE-----
MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG
EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1
OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3
DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k
1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf
GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP
FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu
ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz
Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A
wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF
plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ
EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW
6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI
IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp
E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4
exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M
0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI
84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m
pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd
Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b
E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm
J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
-----END CERTIFICATE-----
SSL.com TLS RSA Root CA 2022
============================
-----BEGIN CERTIFICATE-----
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG
EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg
Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC
VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv
b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u
9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y
7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac
oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M
R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG
D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW
TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk
8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq
g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk
7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud
EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu
N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN
j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by
iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU
o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo
ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib
MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi
vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7
P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0
9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
-----END CERTIFICATE-----
SSL.com TLS ECC Root CA 2022
============================
-----BEGIN CERTIFICATE-----
MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV
UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v
dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx
GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg
Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy
JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1
5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7
81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG
MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w
7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5
Zn6g6g==
-----END CERTIFICATE-----
Atos TrustedRoot Root CA ECC TLS 2021
=====================================
-----BEGIN CERTIFICATE-----
MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB
dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD
VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg
VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT
AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K
DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS
b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX
NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+
uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY
a3cpetskz2VAv9LcjBHo9H1/IISpQuQo
-----END CERTIFICATE-----
Atos TrustedRoot Root CA RSA TLS 2021
=====================================
-----BEGIN CERTIFICATE-----
MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD
DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw
CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0
b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV
BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB
l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG
vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK
ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt
0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK
PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY
sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY
Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+
rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa
fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G
CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS
4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl
Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX
AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G
slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt
afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q
TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj
1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l
PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W
HYMfRsCbvUOZ58SWLs5fyQ==
-----END CERTIFICATE-----
TrustAsia Global Root CA G3
===========================
-----BEGIN CERTIFICATE-----
MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG
A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM
G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw
MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu
MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz
lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ
Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V
P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag
dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm
9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc
D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg
WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea
mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF
TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj
7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E
BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1
D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T
G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj
duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl
cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys
+TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli
2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y
aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS
ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR
JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH
-----END CERTIFICATE-----
TrustAsia Global Root CA G4
===========================
-----BEGIN CERTIFICATE-----
MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE
BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry
dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa
MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw
IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8
m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF
MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/
pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA
bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk
dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
-----END CERTIFICATE-----
CommScope Public Trust ECC Root-01
==================================
-----BEGIN CERTIFICATE-----
MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE
BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz
dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT
AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg
RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx
eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot
6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2
Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW
pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE=
-----END CERTIFICATE-----
CommScope Public Trust ECC Root-02
==================================
-----BEGIN CERTIFICATE-----
MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE
BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz
dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT
AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg
RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M
MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE
SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9
Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7
3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag==
-----END CERTIFICATE-----
CommScope Public Trust RSA Root-01
==================================
-----BEGIN CERTIFICATE-----
MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG
A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU
cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV
BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1
c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft
nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6
uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq
ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs
vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c
Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif
BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9
lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo
KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH
+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4
5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6
NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM
3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck
jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf
Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W
NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+
o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/
oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc
1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM
6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw
-----END CERTIFICATE-----
CommScope Public Trust RSA Root-02
==================================
-----BEGIN CERTIFICATE-----
MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG
A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU
cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV
BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1
c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V
rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx
7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC
e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W
Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp
M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf
hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr
eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE
VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t
Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx
cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB
KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF
1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa
MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd
gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O
HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm
YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr
dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ
iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN
lM47ni3niAIi9G7oyOzWPPO5std3eqx7
-----END CERTIFICATE-----
Telekom Security TLS ECC Root 2020
==================================
-----BEGIN CERTIFICATE-----
MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE
RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl
a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz
NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg
R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG
SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1
2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC
MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ
Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU
ga/sf+Rn27iQ7t0l
-----END CERTIFICATE-----
Telekom Security TLS RSA Root 2023
==================================
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG
EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU
ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy
NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp
dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC
KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP
GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx
UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo
l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9
FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v
zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg
rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML
KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S
WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV
HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2
p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+
sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp
kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy
/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4
mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz
aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa
oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8
wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE
HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0
o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A=
-----END CERTIFICATE-----
FIRMAPROFESIONAL CA ROOT-A WEB
==============================
-----BEGIN CERTIFICATE-----
MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF
UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4
MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2
WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h
bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM
IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6
iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg
st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD
Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB
/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL
cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ
pYXFuXqUPoeovQA=
-----END CERTIFICATE-----
TWCA CYBER Root CA
==================
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG
EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB
IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG
EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB
IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s
Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh
V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT
o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT
Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK
/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH
IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM
fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF
2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR
wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83
QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB
AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN
c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x
X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR
IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq
/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R
FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe
Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv
It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl
IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X
-----END CERTIFICATE-----
SecureSign Root CA12
====================
-----BEGIN CERTIFICATE-----
MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG
A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT
ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ
BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU
U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3
emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc
J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl
fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF
EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef
NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC
AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi
LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce
mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS
vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga
aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA==
-----END CERTIFICATE-----
SecureSign Root CA14
====================
-----BEGIN CERTIFICATE-----
MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG
A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT
ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ
BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU
U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh
1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn
bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb
1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa
/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE
kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx
jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz
ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0
dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY
AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq
YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E
rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA
ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds
Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG
FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q
nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/
OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa
OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO
pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN
eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S
-----END CERTIFICATE-----
SecureSign Root CA15
====================
-----BEGIN CERTIFICATE-----
MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE
BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1
cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV
BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj
dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G
dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB
2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J
fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ
SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=
-----END CERTIFICATE-----
D-TRUST BR Root CA 2 2023
=========================
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG
EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg
MiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT
BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT
cfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z
sWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ
WiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6
++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL
QyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv
x9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV
MweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX
/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9
CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC
MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y
XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr
d6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv
U9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4
nj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij
YQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff
/vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP
pz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB
WoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/
5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt
n/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA==
-----END CERTIFICATE-----
D-TRUST EV Root CA 2 2023
=========================
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG
EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg
MiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT
BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1
sJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/
MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf
vc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM
lWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3
YG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910
7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo
nMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa
QzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF
AZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC
MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y
XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS
Mo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2
QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD
UmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V
4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo
dNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi
TZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi
S5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/
HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L
+KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg==
-----END CERTIFICATE-----
<?php
/**
* Theme, template, and stylesheet functions.
*
* @package WordPress
* @subpackage Theme
*/
/**
* Returns an array of WP_Theme objects based on the arguments.
*
* Despite advances over get_themes(), this function is quite expensive, and grows
* linearly with additional themes. Stick to wp_get_theme() if possible.
*
* @since 3.4.0
*
* @global string[] $wp_theme_directories
*
* @param array $args {
* Optional. The search arguments.
*
* @type mixed $errors True to return themes with errors, false to return
* themes without errors, null to return all themes.
* Default false.
* @type mixed $allowed (Multisite) True to return only allowed themes for a site.
* False to return only disallowed themes for a site.
* 'site' to return only site-allowed themes.
* 'network' to return only network-allowed themes.
* Null to return all themes. Default null.
* @type int $blog_id (Multisite) The blog ID used to calculate which themes
* are allowed. Default 0, synonymous for the current blog.
* }
* @return WP_Theme[] Array of WP_Theme objects.
*/
function wp_get_themes( $args = array() ) {
global $wp_theme_directories;
$defaults = array(
'errors' => false,
'allowed' => null,
'blog_id' => 0,
);
$args = wp_parse_args( $args, $defaults );
$theme_directories = search_theme_directories();
if ( is_array( $wp_theme_directories ) && count( $wp_theme_directories ) > 1 ) {
/*
* Make sure the active theme wins out, in case search_theme_directories() picks the wrong
* one in the case of a conflict. (Normally, last registered theme root wins.)
*/
$current_theme = get_stylesheet();
if ( isset( $theme_directories[ $current_theme ] ) ) {
$root_of_current_theme = get_raw_theme_root( $current_theme );
if ( ! in_array( $root_of_current_theme, $wp_theme_directories, true ) ) {
$root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
}
$theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
}
}
if ( empty( $theme_directories ) ) {
return array();
}
if ( is_multisite() && null !== $args['allowed'] ) {
$allowed = $args['allowed'];
if ( 'network' === $allowed ) {
$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
} elseif ( 'site' === $allowed ) {
$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
} elseif ( $allowed ) {
$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
} else {
$theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
}
}
$themes = array();
static $_themes = array();
foreach ( $theme_directories as $theme => $theme_root ) {
if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) ) {
$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
} else {
$themes[ $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
$_themes[ $theme_root['theme_root'] . '/' . $theme ] = $themes[ $theme ];
}
}
if ( null !== $args['errors'] ) {
foreach ( $themes as $theme => $wp_theme ) {
if ( (bool) $wp_theme->errors() !== $args['errors'] ) {
unset( $themes[ $theme ] );
}
}
}
return $themes;
}
/**
* Gets a WP_Theme object for a theme.
*
* @since 3.4.0
*
* @global string[] $wp_theme_directories
*
* @param string $stylesheet Optional. Directory name for the theme. Defaults to active theme.
* @param string $theme_root Optional. Absolute path of the theme root to look in.
* If not specified, get_raw_theme_root() is used to calculate
* the theme root for the $stylesheet provided (or active theme).
* @return WP_Theme Theme object. Be sure to check the object's exists() method
* if you need to confirm the theme's existence.
*/
function wp_get_theme( $stylesheet = '', $theme_root = '' ) {
global $wp_theme_directories;
if ( empty( $stylesheet ) ) {
$stylesheet = get_stylesheet();
}
if ( empty( $theme_root ) ) {
$theme_root = get_raw_theme_root( $stylesheet );
if ( false === $theme_root ) {
$theme_root = WP_CONTENT_DIR . '/themes';
} elseif ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
$theme_root = WP_CONTENT_DIR . $theme_root;
}
}
return new WP_Theme( $stylesheet, $theme_root );
}
/**
* Clears the cache held by get_theme_roots() and WP_Theme.
*
* @since 3.5.0
* @param bool $clear_update_cache Whether to clear the theme updates cache.
*/
function wp_clean_themes_cache( $clear_update_cache = true ) {
if ( $clear_update_cache ) {
delete_site_transient( 'update_themes' );
}
search_theme_directories( true );
foreach ( wp_get_themes( array( 'errors' => null ) ) as $theme ) {
$theme->cache_delete();
}
}
/**
* Whether a child theme is in use.
*
* @since 3.0.0
* @since 6.5.0 Makes use of global template variables.
*
* @global string $wp_stylesheet_path Path to current theme's stylesheet directory.
* @global string $wp_template_path Path to current theme's template directory.
*
* @return bool True if a child theme is in use, false otherwise.
*/
function is_child_theme() {
global $wp_stylesheet_path, $wp_template_path;
return $wp_stylesheet_path !== $wp_template_path;
}
/**
* Retrieves name of the current stylesheet.
*
* The theme name that is currently set as the front end theme.
*
* For all intents and purposes, the template name and the stylesheet name
* are going to be the same for most cases.
*
* @since 1.5.0
*
* @return string Stylesheet name.
*/
function get_stylesheet() {
/**
* Filters the name of current stylesheet.
*
* @since 1.5.0
*
* @param string $stylesheet Name of the current stylesheet.
*/
return apply_filters( 'stylesheet', get_option( 'stylesheet' ) );
}
/**
* Retrieves stylesheet directory path for the active theme.
*
* @since 1.5.0
* @since 6.4.0 Memoizes filter execution so that it only runs once for the current theme.
* @since 6.4.2 Memoization removed.
*
* @return string Path to active theme's stylesheet directory.
*/
function get_stylesheet_directory() {
$stylesheet = get_stylesheet();
$theme_root = get_theme_root( $stylesheet );
$stylesheet_dir = "$theme_root/$stylesheet";
/**
* Filters the stylesheet directory path for the active theme.
*
* @since 1.5.0
*
* @param string $stylesheet_dir Absolute path to the active theme.
* @param string $stylesheet Directory name of the active theme.
* @param string $theme_root Absolute path to themes directory.
*/
return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
}
/**
* Retrieves stylesheet directory URI for the active theme.
*
* @since 1.5.0
*
* @return string URI to active theme's stylesheet directory.
*/
function get_stylesheet_directory_uri() {
$stylesheet = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) );
$theme_root_uri = get_theme_root_uri( $stylesheet );
$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
/**
* Filters the stylesheet directory URI.
*
* @since 1.5.0
*
* @param string $stylesheet_dir_uri Stylesheet directory URI.
* @param string $stylesheet Name of the activated theme's directory.
* @param string $theme_root_uri Themes root URI.
*/
return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
}
/**
* Retrieves stylesheet URI for the active theme.
*
* The stylesheet file name is 'style.css' which is appended to the stylesheet directory URI path.
* See get_stylesheet_directory_uri().
*
* @since 1.5.0
*
* @return string URI to active theme's stylesheet.
*/
function get_stylesheet_uri() {
$stylesheet_dir_uri = get_stylesheet_directory_uri();
$stylesheet_uri = $stylesheet_dir_uri . '/style.css';
/**
* Filters the URI of the active theme stylesheet.
*
* @since 1.5.0
*
* @param string $stylesheet_uri Stylesheet URI for the active theme/child theme.
* @param string $stylesheet_dir_uri Stylesheet directory URI for the active theme/child theme.
*/
return apply_filters( 'stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri );
}
/**
* Retrieves the localized stylesheet URI.
*
* The stylesheet directory for the localized stylesheet files are located, by
* default, in the base theme directory. The name of the locale file will be the
* locale followed by '.css'. If that does not exist, then the text direction
* stylesheet will be checked for existence, for example 'ltr.css'.
*
* The theme may change the location of the stylesheet directory by either using
* the {@see 'stylesheet_directory_uri'} or {@see 'locale_stylesheet_uri'} filters.
*
* If you want to change the location of the stylesheet files for the entire
* WordPress workflow, then change the former. If you just have the locale in a
* separate folder, then change the latter.
*
* @since 2.1.0
*
* @global WP_Locale $wp_locale WordPress date and time locale object.
*
* @return string URI to active theme's localized stylesheet.
*/
function get_locale_stylesheet_uri() {
global $wp_locale;
$stylesheet_dir_uri = get_stylesheet_directory_uri();
$dir = get_stylesheet_directory();
$locale = get_locale();
if ( file_exists( "$dir/$locale.css" ) ) {
$stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
} elseif ( ! empty( $wp_locale->text_direction ) && file_exists( "$dir/{$wp_locale->text_direction}.css" ) ) {
$stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
} else {
$stylesheet_uri = '';
}
/**
* Filters the localized stylesheet URI.
*
* @since 2.1.0
*
* @param string $stylesheet_uri Localized stylesheet URI.
* @param string $stylesheet_dir_uri Stylesheet directory URI.
*/
return apply_filters( 'locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri );
}
/**
* Retrieves name of the active theme.
*
* @since 1.5.0
*
* @return string Template name.
*/
function get_template() {
/**
* Filters the name of the active theme.
*
* @since 1.5.0
*
* @param string $template active theme's directory name.
*/
return apply_filters( 'template', get_option( 'template' ) );
}
/**
* Retrieves template directory path for the active theme.
*
* @since 1.5.0
* @since 6.4.0 Memoizes filter execution so that it only runs once for the current theme.
* @since 6.4.1 Memoization removed.
*
* @return string Path to active theme's template directory.
*/
function get_template_directory() {
$template = get_template();
$theme_root = get_theme_root( $template );
$template_dir = "$theme_root/$template";
/**
* Filters the active theme directory path.
*
* @since 1.5.0
*
* @param string $template_dir The path of the active theme directory.
* @param string $template Directory name of the active theme.
* @param string $theme_root Absolute path to the themes directory.
*/
return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
}
/**
* Retrieves template directory URI for the active theme.
*
* @since 1.5.0
*
* @return string URI to active theme's template directory.
*/
function get_template_directory_uri() {
$template = str_replace( '%2F', '/', rawurlencode( get_template() ) );
$theme_root_uri = get_theme_root_uri( $template );
$template_dir_uri = "$theme_root_uri/$template";
/**
* Filters the active theme directory URI.
*
* @since 1.5.0
*
* @param string $template_dir_uri The URI of the active theme directory.
* @param string $template Directory name of the active theme.
* @param string $theme_root_uri The themes root URI.
*/
return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
}
/**
* Retrieves theme roots.
*
* @since 2.9.0
*
* @global string[] $wp_theme_directories
*
* @return array|string An array of theme roots keyed by template/stylesheet
* or a single theme root if all themes have the same root.
*/
function get_theme_roots() {
global $wp_theme_directories;
if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
return '/themes';
}
$theme_roots = get_site_transient( 'theme_roots' );
if ( false === $theme_roots ) {
search_theme_directories( true ); // Regenerate the transient.
$theme_roots = get_site_transient( 'theme_roots' );
}
return $theme_roots;
}
/**
* Registers a directory that contains themes.
*
* @since 2.9.0
*
* @global string[] $wp_theme_directories
*
* @param string $directory Either the full filesystem path to a theme folder
* or a folder within WP_CONTENT_DIR.
* @return bool True if successfully registered a directory that contains themes,
* false if the directory does not exist.
*/
function register_theme_directory( $directory ) {
global $wp_theme_directories;
if ( ! file_exists( $directory ) ) {
// Try prepending as the theme directory could be relative to the content directory.
$directory = WP_CONTENT_DIR . '/' . $directory;
// If this directory does not exist, return and do not register.
if ( ! file_exists( $directory ) ) {
return false;
}
}
if ( ! is_array( $wp_theme_directories ) ) {
$wp_theme_directories = array();
}
$untrailed = untrailingslashit( $directory );
if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories, true ) ) {
$wp_theme_directories[] = $untrailed;
}
return true;
}
/**
* Searches all registered theme directories for complete and valid themes.
*
* @since 2.9.0
*
* @global string[] $wp_theme_directories
*
* @param bool $force Optional. Whether to force a new directory scan. Default false.
* @return array|false Valid themes found on success, false on failure.
*/
function search_theme_directories( $force = false ) {
global $wp_theme_directories;
static $found_themes = null;
if ( empty( $wp_theme_directories ) ) {
return false;
}
if ( ! $force && isset( $found_themes ) ) {
return $found_themes;
}
$found_themes = array();
$wp_theme_directories = (array) $wp_theme_directories;
$relative_theme_roots = array();
/*
* Set up maybe-relative, maybe-absolute array of theme directories.
* We always want to return absolute, but we need to cache relative
* to use in get_theme_root().
*/
foreach ( $wp_theme_directories as $theme_root ) {
if ( str_starts_with( $theme_root, WP_CONTENT_DIR ) ) {
$relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
} else {
$relative_theme_roots[ $theme_root ] = $theme_root;
}
}
/**
* Filters whether to get the cache of the registered theme directories.
*
* @since 3.4.0
*
* @param bool $cache_expiration Whether to get the cache of the theme directories. Default false.
* @param string $context The class or function name calling the filter.
*/
$cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' );
if ( $cache_expiration ) {
$cached_roots = get_site_transient( 'theme_roots' );
if ( is_array( $cached_roots ) ) {
foreach ( $cached_roots as $theme_dir => $theme_root ) {
// A cached theme root is no longer around, so skip it.
if ( ! isset( $relative_theme_roots[ $theme_root ] ) ) {
continue;
}
$found_themes[ $theme_dir ] = array(
'theme_file' => $theme_dir . '/style.css',
'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
);
}
return $found_themes;
}
if ( ! is_int( $cache_expiration ) ) {
$cache_expiration = 30 * MINUTE_IN_SECONDS;
}
} else {
$cache_expiration = 30 * MINUTE_IN_SECONDS;
}
/* Loop the registered theme directories and extract all themes */
foreach ( $wp_theme_directories as $theme_root ) {
// Start with directories in the root of the active theme directory.
$dirs = @ scandir( $theme_root );
if ( ! $dirs ) {
wp_trigger_error( __FUNCTION__, "$theme_root is not readable" );
continue;
}
foreach ( $dirs as $dir ) {
if ( ! is_dir( $theme_root . '/' . $dir ) || '.' === $dir[0] || 'CVS' === $dir ) {
continue;
}
if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
/*
* wp-content/themes/a-single-theme
* wp-content/themes is $theme_root, a-single-theme is $dir.
*/
$found_themes[ $dir ] = array(
'theme_file' => $dir . '/style.css',
'theme_root' => $theme_root,
);
} else {
$found_theme = false;
/*
* wp-content/themes/a-folder-of-themes/*
* wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs.
*/
$sub_dirs = @ scandir( $theme_root . '/' . $dir );
if ( ! $sub_dirs ) {
wp_trigger_error( __FUNCTION__, "$theme_root/$dir is not readable" );
continue;
}
foreach ( $sub_dirs as $sub_dir ) {
if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || '.' === $dir[0] || 'CVS' === $dir ) {
continue;
}
if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) ) {
continue;
}
$found_themes[ $dir . '/' . $sub_dir ] = array(
'theme_file' => $dir . '/' . $sub_dir . '/style.css',
'theme_root' => $theme_root,
);
$found_theme = true;
}
/*
* Never mind the above, it's just a theme missing a style.css.
* Return it; WP_Theme will catch the error.
*/
if ( ! $found_theme ) {
$found_themes[ $dir ] = array(
'theme_file' => $dir . '/style.css',
'theme_root' => $theme_root,
);
}
}
}
}
asort( $found_themes );
$theme_roots = array();
$relative_theme_roots = array_flip( $relative_theme_roots );
foreach ( $found_themes as $theme_dir => $theme_data ) {
$theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
}
if ( get_site_transient( 'theme_roots' ) !== $theme_roots ) {
set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
}
return $found_themes;
}
/**
* Retrieves path to themes directory.
*
* Does not have trailing slash.
*
* @since 1.5.0
*
* @global string[] $wp_theme_directories
*
* @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
* Default is to leverage the main theme root.
* @return string Themes directory path.
*/
function get_theme_root( $stylesheet_or_template = '' ) {
global $wp_theme_directories;
$theme_root = '';
if ( $stylesheet_or_template ) {
$theme_root = get_raw_theme_root( $stylesheet_or_template );
if ( $theme_root ) {
/*
* Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
* This gives relative theme roots the benefit of the doubt when things go haywire.
*/
if ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
$theme_root = WP_CONTENT_DIR . $theme_root;
}
}
}
if ( ! $theme_root ) {
$theme_root = WP_CONTENT_DIR . '/themes';
}
/**
* Filters the absolute path to the themes directory.
*
* @since 1.5.0
*
* @param string $theme_root Absolute path to themes directory.
*/
return apply_filters( 'theme_root', $theme_root );
}
/**
* Retrieves URI for themes directory.
*
* Does not have trailing slash.
*
* @since 1.5.0
*
* @global string[] $wp_theme_directories
*
* @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
* Default is to leverage the main theme root.
* @param string $theme_root Optional. The theme root for which calculations will be based,
* preventing the need for a get_raw_theme_root() call. Default empty.
* @return string Themes directory URI.
*/
function get_theme_root_uri( $stylesheet_or_template = '', $theme_root = '' ) {
global $wp_theme_directories;
if ( $stylesheet_or_template && ! $theme_root ) {
$theme_root = get_raw_theme_root( $stylesheet_or_template );
}
if ( $stylesheet_or_template && $theme_root ) {
if ( in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
// Absolute path. Make an educated guess. YMMV -- but note the filter below.
if ( str_starts_with( $theme_root, WP_CONTENT_DIR ) ) {
$theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
} elseif ( str_starts_with( $theme_root, ABSPATH ) ) {
$theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
} elseif ( str_starts_with( $theme_root, WP_PLUGIN_DIR ) || str_starts_with( $theme_root, WPMU_PLUGIN_DIR ) ) {
$theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
} else {
$theme_root_uri = $theme_root;
}
} else {
$theme_root_uri = content_url( $theme_root );
}
} else {
$theme_root_uri = content_url( 'themes' );
}
/**
* Filters the URI for themes directory.
*
* @since 1.5.0
*
* @param string $theme_root_uri The URI for themes directory.
* @param string $siteurl WordPress web address which is set in General Options.
* @param string $stylesheet_or_template The stylesheet or template name of the theme.
*/
return apply_filters( 'theme_root_uri', $theme_root_uri, get_option( 'siteurl' ), $stylesheet_or_template );
}
/**
* Gets the raw theme root relative to the content directory with no filters applied.
*
* @since 3.1.0
*
* @global string[] $wp_theme_directories
*
* @param string $stylesheet_or_template The stylesheet or template name of the theme.
* @param bool $skip_cache Optional. Whether to skip the cache.
* Defaults to false, meaning the cache is used.
* @return string Theme root.
*/
function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
global $wp_theme_directories;
if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
return '/themes';
}
$theme_root = false;
// If requesting the root for the active theme, consult options to avoid calling get_theme_roots().
if ( ! $skip_cache ) {
if ( get_option( 'stylesheet' ) === $stylesheet_or_template ) {
$theme_root = get_option( 'stylesheet_root' );
} elseif ( get_option( 'template' ) === $stylesheet_or_template ) {
$theme_root = get_option( 'template_root' );
}
}
if ( empty( $theme_root ) ) {
$theme_roots = get_theme_roots();
if ( ! empty( $theme_roots[ $stylesheet_or_template ] ) ) {
$theme_root = $theme_roots[ $stylesheet_or_template ];
}
}
return $theme_root;
}
/**
* Displays localized stylesheet link element.
*
* @since 2.1.0
*/
function locale_stylesheet() {
$stylesheet = get_locale_stylesheet_uri();
if ( empty( $stylesheet ) ) {
return;
}
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
printf(
'<link rel="stylesheet" href="%s"%s media="screen" />',
$stylesheet,
$type_attr
);
}
/**
* Switches the theme.
*
* Accepts one argument: $stylesheet of the theme. It also accepts an additional function signature
* of two arguments: $template then $stylesheet. This is for backward compatibility.
*
* @since 2.5.0
*
* @global string[] $wp_theme_directories
* @global WP_Customize_Manager $wp_customize
* @global array $sidebars_widgets
* @global array $wp_registered_sidebars
*
* @param string $stylesheet Stylesheet name.
*/
function switch_theme( $stylesheet ) {
global $wp_theme_directories, $wp_customize, $sidebars_widgets, $wp_registered_sidebars;
$requirements = validate_theme_requirements( $stylesheet );
if ( is_wp_error( $requirements ) ) {
wp_die( $requirements );
}
$_sidebars_widgets = null;
if ( 'wp_ajax_customize_save' === current_action() ) {
$old_sidebars_widgets_data_setting = $wp_customize->get_setting( 'old_sidebars_widgets_data' );
if ( $old_sidebars_widgets_data_setting ) {
$_sidebars_widgets = $wp_customize->post_value( $old_sidebars_widgets_data_setting );
}
} elseif ( is_array( $sidebars_widgets ) ) {
$_sidebars_widgets = $sidebars_widgets;
}
if ( is_array( $_sidebars_widgets ) ) {
set_theme_mod(
'sidebars_widgets',
array(
'time' => time(),
'data' => $_sidebars_widgets,
)
);
}
$nav_menu_locations = get_theme_mod( 'nav_menu_locations' );
update_option( 'theme_switch_menu_locations', $nav_menu_locations, true );
if ( func_num_args() > 1 ) {
$stylesheet = func_get_arg( 1 );
}
$old_theme = wp_get_theme();
$new_theme = wp_get_theme( $stylesheet );
$template = $new_theme->get_template();
if ( wp_is_recovery_mode() ) {
$paused_themes = wp_paused_themes();
$paused_themes->delete( $old_theme->get_stylesheet() );
$paused_themes->delete( $old_theme->get_template() );
}
update_option( 'template', $template );
update_option( 'stylesheet', $stylesheet );
if ( count( $wp_theme_directories ) > 1 ) {
update_option( 'template_root', get_raw_theme_root( $template, true ) );
update_option( 'stylesheet_root', get_raw_theme_root( $stylesheet, true ) );
} else {
delete_option( 'template_root' );
delete_option( 'stylesheet_root' );
}
$new_name = $new_theme->get( 'Name' );
update_option( 'current_theme', $new_name );
// Migrate from the old mods_{name} option to theme_mods_{slug}.
if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
$default_theme_mods = (array) get_option( 'mods_' . $new_name );
if ( ! empty( $nav_menu_locations ) && empty( $default_theme_mods['nav_menu_locations'] ) ) {
$default_theme_mods['nav_menu_locations'] = $nav_menu_locations;
}
add_option( "theme_mods_$stylesheet", $default_theme_mods );
} else {
/*
* Since retrieve_widgets() is called when initializing a theme in the Customizer,
* we need to remove the theme mods to avoid overwriting changes made via
* the Customizer when accessing wp-admin/widgets.php.
*/
if ( 'wp_ajax_customize_save' === current_action() ) {
remove_theme_mod( 'sidebars_widgets' );
}
}
// Stores classic sidebars for later use by block themes.
if ( $new_theme->is_block_theme() ) {
set_theme_mod( 'wp_classic_sidebars', $wp_registered_sidebars );
}
update_option( 'theme_switched', $old_theme->get_stylesheet() );
/*
* Reset template globals when switching themes outside of a switched blog
* context to ensure templates will be loaded from the new theme.
*/
if ( ! is_multisite() || ! ms_is_switched() ) {
wp_set_template_globals();
}
// Clear pattern caches.
if ( ! is_multisite() ) {
$new_theme->delete_pattern_cache();
$old_theme->delete_pattern_cache();
}
// Set autoload=no for the old theme, autoload=yes for the switched theme.
$theme_mods_options = array(
'theme_mods_' . $stylesheet => 'yes',
'theme_mods_' . $old_theme->get_stylesheet() => 'no',
);
wp_set_option_autoload_values( $theme_mods_options );
/**
* Fires after the theme is switched.
*
* See {@see 'after_switch_theme'}.
*
* @since 1.5.0
* @since 4.5.0 Introduced the `$old_theme` parameter.
*
* @param string $new_name Name of the new theme.
* @param WP_Theme $new_theme WP_Theme instance of the new theme.
* @param WP_Theme $old_theme WP_Theme instance of the old theme.
*/
do_action( 'switch_theme', $new_name, $new_theme, $old_theme );
}
/**
* Checks that the active theme has the required files.
*
* Standalone themes need to have a `templates/index.html` or `index.php` template file.
* Child themes need to have a `Template` header in the `style.css` stylesheet.
*
* Does not initially check the default theme, which is the fallback and should always exist.
* But if it doesn't exist, it'll fall back to the latest core default theme that does exist.
* Will switch theme to the fallback theme if active theme does not validate.
*
* You can use the {@see 'validate_current_theme'} filter to return false to disable
* this functionality.
*
* @since 1.5.0
* @since 6.0.0 Removed the requirement for block themes to have an `index.php` template.
*
* @see WP_DEFAULT_THEME
*
* @return bool
*/
function validate_current_theme() {
/**
* Filters whether to validate the active theme.
*
* @since 2.7.0
*
* @param bool $validate Whether to validate the active theme. Default true.
*/
if ( wp_installing() || ! apply_filters( 'validate_current_theme', true ) ) {
return true;
}
if (
! file_exists( get_template_directory() . '/templates/index.html' )
&& ! file_exists( get_template_directory() . '/block-templates/index.html' ) // Deprecated path support since 5.9.0.
&& ! file_exists( get_template_directory() . '/index.php' )
) {
// Invalid.
} elseif ( ! file_exists( get_template_directory() . '/style.css' ) ) {
// Invalid.
} elseif ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
// Invalid.
} else {
// Valid.
return true;
}
$default = wp_get_theme( WP_DEFAULT_THEME );
if ( $default->exists() ) {
switch_theme( WP_DEFAULT_THEME );
return false;
}
/**
* If we're in an invalid state but WP_DEFAULT_THEME doesn't exist,
* switch to the latest core default theme that's installed.
*
* If it turns out that this latest core default theme is our current
* theme, then there's nothing we can do about that, so we have to bail,
* rather than going into an infinite loop. (This is why there are
* checks against WP_DEFAULT_THEME above, also.) We also can't do anything
* if it turns out there is no default theme installed. (That's `false`.)
*/
$default = WP_Theme::get_core_default_theme();
if ( false === $default || get_stylesheet() === $default->get_stylesheet() ) {
return true;
}
switch_theme( $default->get_stylesheet() );
return false;
}
/**
* Validates the theme requirements for WordPress version and PHP version.
*
* Uses the information from `Requires at least` and `Requires PHP` headers
* defined in the theme's `style.css` file.
*
* @since 5.5.0
* @since 5.8.0 Removed support for using `readme.txt` as a fallback.
*
* @param string $stylesheet Directory name for the theme.
* @return true|WP_Error True if requirements are met, WP_Error on failure.
*/
function validate_theme_requirements( $stylesheet ) {
$theme = wp_get_theme( $stylesheet );
$requirements = array(
'requires' => ! empty( $theme->get( 'RequiresWP' ) ) ? $theme->get( 'RequiresWP' ) : '',
'requires_php' => ! empty( $theme->get( 'RequiresPHP' ) ) ? $theme->get( 'RequiresPHP' ) : '',
);
$compatible_wp = is_wp_version_compatible( $requirements['requires'] );
$compatible_php = is_php_version_compatible( $requirements['requires_php'] );
if ( ! $compatible_wp && ! $compatible_php ) {
return new WP_Error(
'theme_wp_php_incompatible',
sprintf(
/* translators: %s: Theme name. */
_x( '<strong>Error:</strong> Current WordPress and PHP versions do not meet minimum requirements for %s.', 'theme' ),
$theme->display( 'Name' )
)
);
} elseif ( ! $compatible_php ) {
return new WP_Error(
'theme_php_incompatible',
sprintf(
/* translators: %s: Theme name. */
_x( '<strong>Error:</strong> Current PHP version does not meet minimum requirements for %s.', 'theme' ),
$theme->display( 'Name' )
)
);
} elseif ( ! $compatible_wp ) {
return new WP_Error(
'theme_wp_incompatible',
sprintf(
/* translators: %s: Theme name. */
_x( '<strong>Error:</strong> Current WordPress version does not meet minimum requirements for %s.', 'theme' ),
$theme->display( 'Name' )
)
);
}
return true;
}
/**
* Retrieves all theme modifications.
*
* @since 3.1.0
* @since 5.9.0 The return value is always an array.
*
* @return array Theme modifications.
*/
function get_theme_mods() {
$theme_slug = get_option( 'stylesheet' );
$mods = get_option( "theme_mods_$theme_slug" );
if ( false === $mods ) {
$theme_name = get_option( 'current_theme' );
if ( false === $theme_name ) {
$theme_name = wp_get_theme()->get( 'Name' );
}
$mods = get_option( "mods_$theme_name" ); // Deprecated location.
if ( is_admin() && false !== $mods ) {
update_option( "theme_mods_$theme_slug", $mods );
delete_option( "mods_$theme_name" );
}
}
if ( ! is_array( $mods ) ) {
$mods = array();
}
return $mods;
}
/**
* Retrieves theme modification value for the active theme.
*
* If the modification name does not exist and `$default_value` is a string, then the
* default will be passed through the {@link https://www.php.net/sprintf sprintf()}
* PHP function with the template directory URI as the first value and the
* stylesheet directory URI as the second value.
*
* @since 2.1.0
*
* @param string $name Theme modification name.
* @param mixed $default_value Optional. Theme modification default value. Default false.
* @return mixed Theme modification value.
*/
function get_theme_mod( $name, $default_value = false ) {
$mods = get_theme_mods();
if ( isset( $mods[ $name ] ) ) {
/**
* Filters the theme modification, or 'theme_mod', value.
*
* The dynamic portion of the hook name, `$name`, refers to the key name
* of the modification array. For example, 'header_textcolor', 'header_image',
* and so on depending on the theme options.
*
* @since 2.2.0
*
* @param mixed $current_mod The value of the active theme modification.
*/
return apply_filters( "theme_mod_{$name}", $mods[ $name ] );
}
if ( is_string( $default_value ) ) {
// Only run the replacement if an sprintf() string format pattern was found.
if ( preg_match( '#(?<!%)%(?:\d+\$?)?s#', $default_value ) ) {
// Remove a single trailing percent sign.
$default_value = preg_replace( '#(?<!%)%$#', '', $default_value );
$default_value = sprintf( $default_value, get_template_directory_uri(), get_stylesheet_directory_uri() );
}
}
/** This filter is documented in wp-includes/theme.php */
return apply_filters( "theme_mod_{$name}", $default_value );
}
/**
* Updates theme modification value for the active theme.
*
* @since 2.1.0
* @since 5.6.0 A return value was added.
*
* @param string $name Theme modification name.
* @param mixed $value Theme modification value.
* @return bool True if the value was updated, false otherwise.
*/
function set_theme_mod( $name, $value ) {
$mods = get_theme_mods();
$old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;
/**
* Filters the theme modification, or 'theme_mod', value on save.
*
* The dynamic portion of the hook name, `$name`, refers to the key name
* of the modification array. For example, 'header_textcolor', 'header_image',
* and so on depending on the theme options.
*
* @since 3.9.0
*
* @param mixed $value The new value of the theme modification.
* @param mixed $old_value The current value of the theme modification.
*/
$mods[ $name ] = apply_filters( "pre_set_theme_mod_{$name}", $value, $old_value );
$theme = get_option( 'stylesheet' );
return update_option( "theme_mods_$theme", $mods );
}
/**
* Removes theme modification name from active theme list.
*
* If removing the name also removes all elements, then the entire option
* will be removed.
*
* @since 2.1.0
*
* @param string $name Theme modification name.
*/
function remove_theme_mod( $name ) {
$mods = get_theme_mods();
if ( ! isset( $mods[ $name ] ) ) {
return;
}
unset( $mods[ $name ] );
if ( empty( $mods ) ) {
remove_theme_mods();
return;
}
$theme = get_option( 'stylesheet' );
update_option( "theme_mods_$theme", $mods );
}
/**
* Removes theme modifications option for the active theme.
*
* @since 2.1.0
*/
function remove_theme_mods() {
delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
// Old style.
$theme_name = get_option( 'current_theme' );
if ( false === $theme_name ) {
$theme_name = wp_get_theme()->get( 'Name' );
}
delete_option( 'mods_' . $theme_name );
}
/**
* Retrieves the custom header text color in 3- or 6-digit hexadecimal form.
*
* @since 2.1.0
*
* @return string Header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
*/
function get_header_textcolor() {
return get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
}
/**
* Displays the custom header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
*
* @since 2.1.0
*/
function header_textcolor() {
echo get_header_textcolor();
}
/**
* Whether to display the header text.
*
* @since 3.4.0
*
* @return bool
*/
function display_header_text() {
if ( ! current_theme_supports( 'custom-header', 'header-text' ) ) {
return false;
}
$text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
return 'blank' !== $text_color;
}
/**
* Checks whether a header image is set or not.
*
* @since 4.2.0
*
* @see get_header_image()
*
* @return bool Whether a header image is set or not.
*/
function has_header_image() {
return (bool) get_header_image();
}
/**
* Retrieves header image for custom header.
*
* @since 2.1.0
*
* @return string|false
*/
function get_header_image() {
$url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
if ( 'remove-header' === $url ) {
return false;
}
if ( is_random_header_image() ) {
$url = get_random_header_image();
}
/**
* Filters the header image URL.
*
* @since 6.1.0
*
* @param string $url Header image URL.
*/
$url = apply_filters( 'get_header_image', $url );
if ( ! is_string( $url ) ) {
return false;
}
$url = trim( $url );
return sanitize_url( set_url_scheme( $url ) );
}
/**
* Creates image tag markup for a custom header image.
*
* @since 4.4.0
*
* @param array $attr Optional. Additional attributes for the image tag. Can be used
* to override the default attributes. Default empty.
* @return string HTML image element markup or empty string on failure.
*/
function get_header_image_tag( $attr = array() ) {
$header = get_custom_header();
$header->url = get_header_image();
if ( ! $header->url ) {
return '';
}
$width = absint( $header->width );
$height = absint( $header->height );
$alt = '';
// Use alternative text assigned to the image, if available. Otherwise, leave it empty.
if ( ! empty( $header->attachment_id ) ) {
$image_alt = get_post_meta( $header->attachment_id, '_wp_attachment_image_alt', true );
if ( is_string( $image_alt ) ) {
$alt = $image_alt;
}
}
$attr = wp_parse_args(
$attr,
array(
'src' => $header->url,
'width' => $width,
'height' => $height,
'alt' => $alt,
)
);
// Generate 'srcset' and 'sizes' if not already present.
if ( empty( $attr['srcset'] ) && ! empty( $header->attachment_id ) ) {
$image_meta = get_post_meta( $header->attachment_id, '_wp_attachment_metadata', true );
$size_array = array( $width, $height );
if ( is_array( $image_meta ) ) {
$srcset = wp_calculate_image_srcset( $size_array, $header->url, $image_meta, $header->attachment_id );
if ( ! empty( $attr['sizes'] ) ) {
$sizes = $attr['sizes'];
} else {
$sizes = wp_calculate_image_sizes( $size_array, $header->url, $image_meta, $header->attachment_id );
}
if ( $srcset && $sizes ) {
$attr['srcset'] = $srcset;
$attr['sizes'] = $sizes;
}
}
}
$attr = array_merge(
$attr,
wp_get_loading_optimization_attributes( 'img', $attr, 'get_header_image_tag' )
);
/*
* If the default value of `lazy` for the `loading` attribute is overridden
* to omit the attribute for this image, ensure it is not included.
*/
if ( isset( $attr['loading'] ) && ! $attr['loading'] ) {
unset( $attr['loading'] );
}
// If the `fetchpriority` attribute is overridden and set to false or an empty string.
if ( isset( $attr['fetchpriority'] ) && ! $attr['fetchpriority'] ) {
unset( $attr['fetchpriority'] );
}
// If the `decoding` attribute is overridden and set to false or an empty string.
if ( isset( $attr['decoding'] ) && ! $attr['decoding'] ) {
unset( $attr['decoding'] );
}
/**
* Filters the list of header image attributes.
*
* @since 5.9.0
*
* @param array $attr Array of the attributes for the image tag.
* @param object $header The custom header object returned by 'get_custom_header()'.
*/
$attr = apply_filters( 'get_header_image_tag_attributes', $attr, $header );
$attr = array_map( 'esc_attr', $attr );
$html = '<img';
foreach ( $attr as $name => $value ) {
$html .= ' ' . $name . '="' . $value . '"';
}
$html .= ' />';
/**
* Filters the markup of header images.
*
* @since 4.4.0
*
* @param string $html The HTML image tag markup being filtered.
* @param object $header The custom header object returned by 'get_custom_header()'.
* @param array $attr Array of the attributes for the image tag.
*/
return apply_filters( 'get_header_image_tag', $html, $header, $attr );
}
/**
* Displays the image markup for a custom header image.
*
* @since 4.4.0
*
* @param array $attr Optional. Attributes for the image markup. Default empty.
*/
function the_header_image_tag( $attr = array() ) {
echo get_header_image_tag( $attr );
}
/**
* Gets random header image data from registered images in theme.
*
* @since 3.4.0
*
* @access private
*
* @global array $_wp_default_headers
*
* @return object
*/
function _get_random_header_data() {
global $_wp_default_headers;
static $_wp_random_header = null;
if ( empty( $_wp_random_header ) ) {
$header_image_mod = get_theme_mod( 'header_image', '' );
$headers = array();
if ( 'random-uploaded-image' === $header_image_mod ) {
$headers = get_uploaded_header_images();
} elseif ( ! empty( $_wp_default_headers ) ) {
if ( 'random-default-image' === $header_image_mod ) {
$headers = $_wp_default_headers;
} else {
if ( current_theme_supports( 'custom-header', 'random-default' ) ) {
$headers = $_wp_default_headers;
}
}
}
if ( empty( $headers ) ) {
return new stdClass();
}
$_wp_random_header = (object) $headers[ array_rand( $headers ) ];
$_wp_random_header->url = sprintf(
$_wp_random_header->url,
get_template_directory_uri(),
get_stylesheet_directory_uri()
);
$_wp_random_header->thumbnail_url = sprintf(
$_wp_random_header->thumbnail_url,
get_template_directory_uri(),
get_stylesheet_directory_uri()
);
}
return $_wp_random_header;
}
/**
* Gets random header image URL from registered images in theme.
*
* @since 3.2.0
*
* @return string Path to header image.
*/
function get_random_header_image() {
$random_image = _get_random_header_data();
if ( empty( $random_image->url ) ) {
return '';
}
return $random_image->url;
}
/**
* Checks if random header image is in use.
*
* Always true if user expressly chooses the option in Appearance > Header.
* Also true if theme has multiple header images registered, no specific header image
* is chosen, and theme turns on random headers with add_theme_support().
*
* @since 3.2.0
*
* @param string $type The random pool to use. Possible values include 'any',
* 'default', 'uploaded'. Default 'any'.
* @return bool
*/
function is_random_header_image( $type = 'any' ) {
$header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
if ( 'any' === $type ) {
if ( 'random-default-image' === $header_image_mod
|| 'random-uploaded-image' === $header_image_mod
|| ( empty( $header_image_mod ) && '' !== get_random_header_image() )
) {
return true;
}
} else {
if ( "random-$type-image" === $header_image_mod ) {
return true;
} elseif ( 'default' === $type
&& empty( $header_image_mod ) && '' !== get_random_header_image()
) {
return true;
}
}
return false;
}
/**
* Displays header image URL.
*
* @since 2.1.0
*/
function header_image() {
$image = get_header_image();
if ( $image ) {
echo esc_url( $image );
}
}
/**
* Gets the header images uploaded for the active theme.
*
* @since 3.2.0
*
* @return array
*/
function get_uploaded_header_images() {
$header_images = array();
// @todo Caching.
$headers = get_posts(
array(
'post_type' => 'attachment',
'meta_key' => '_wp_attachment_is_custom_header',
'meta_value' => get_option( 'stylesheet' ),
'orderby' => 'none',
'nopaging' => true,
)
);
if ( empty( $headers ) ) {
return array();
}
foreach ( (array) $headers as $header ) {
$url = sanitize_url( wp_get_attachment_url( $header->ID ) );
$header_data = wp_get_attachment_metadata( $header->ID );
$header_index = $header->ID;
$header_images[ $header_index ] = array();
$header_images[ $header_index ]['attachment_id'] = $header->ID;
$header_images[ $header_index ]['url'] = $url;
$header_images[ $header_index ]['thumbnail_url'] = $url;
$header_images[ $header_index ]['alt_text'] = get_post_meta( $header->ID, '_wp_attachment_image_alt', true );
if ( isset( $header_data['attachment_parent'] ) ) {
$header_images[ $header_index ]['attachment_parent'] = $header_data['attachment_parent'];
} else {
$header_images[ $header_index ]['attachment_parent'] = '';
}
if ( isset( $header_data['width'] ) ) {
$header_images[ $header_index ]['width'] = $header_data['width'];
}
if ( isset( $header_data['height'] ) ) {
$header_images[ $header_index ]['height'] = $header_data['height'];
}
}
return $header_images;
}
/**
* Gets the header image data.
*
* @since 3.4.0
*
* @global array $_wp_default_headers
*
* @return object
*/
function get_custom_header() {
global $_wp_default_headers;
if ( is_random_header_image() ) {
$data = _get_random_header_data();
} else {
$data = get_theme_mod( 'header_image_data' );
if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
$directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
$data = array();
$data['url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
$data['thumbnail_url'] = $data['url'];
if ( ! empty( $_wp_default_headers ) ) {
foreach ( (array) $_wp_default_headers as $default_header ) {
$url = vsprintf( $default_header['url'], $directory_args );
if ( $data['url'] === $url ) {
$data = $default_header;
$data['url'] = $url;
$data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
break;
}
}
}
}
}
$default = array(
'url' => '',
'thumbnail_url' => '',
'width' => get_theme_support( 'custom-header', 'width' ),
'height' => get_theme_support( 'custom-header', 'height' ),
'video' => get_theme_support( 'custom-header', 'video' ),
);
return (object) wp_parse_args( $data, $default );
}
/**
* Registers a selection of default headers to be displayed by the custom header admin UI.
*
* @since 3.0.0
*
* @global array $_wp_default_headers
*
* @param array $headers Array of headers keyed by a string ID. The IDs point to arrays
* containing 'url', 'thumbnail_url', and 'description' keys.
*/
function register_default_headers( $headers ) {
global $_wp_default_headers;
$_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
}
/**
* Unregisters default headers.
*
* This function must be called after register_default_headers() has already added the
* header you want to remove.
*
* @see register_default_headers()
* @since 3.0.0
*
* @global array $_wp_default_headers
*
* @param string|array $header The header string id (key of array) to remove, or an array thereof.
* @return bool|void A single header returns true on success, false on failure.
* There is currently no return value for multiple headers.
*/
function unregister_default_headers( $header ) {
global $_wp_default_headers;
if ( is_array( $header ) ) {
array_map( 'unregister_default_headers', $header );
} elseif ( isset( $_wp_default_headers[ $header ] ) ) {
unset( $_wp_default_headers[ $header ] );
return true;
} else {
return false;
}
}
/**
* Checks whether a header video is set or not.
*
* @since 4.7.0
*
* @see get_header_video_url()
*
* @return bool Whether a header video is set or not.
*/
function has_header_video() {
return (bool) get_header_video_url();
}
/**
* Retrieves header video URL for custom header.
*
* Uses a local video if present, or falls back to an external video.
*
* @since 4.7.0
*
* @return string|false Header video URL or false if there is no video.
*/
function get_header_video_url() {
$id = absint( get_theme_mod( 'header_video' ) );
if ( $id ) {
// Get the file URL from the attachment ID.
$url = wp_get_attachment_url( $id );
} else {
$url = get_theme_mod( 'external_header_video' );
}
/**
* Filters the header video URL.
*
* @since 4.7.3
*
* @param string $url Header video URL, if available.
*/
$url = apply_filters( 'get_header_video_url', $url );
if ( ! $id && ! $url ) {
return false;
}
return sanitize_url( set_url_scheme( $url ) );
}
/**
* Displays header video URL.
*
* @since 4.7.0
*/
function the_header_video_url() {
$video = get_header_video_url();
if ( $video ) {
echo esc_url( $video );
}
}
/**
* Retrieves header video settings.
*
* @since 4.7.0
*
* @return array
*/
function get_header_video_settings() {
$header = get_custom_header();
$video_url = get_header_video_url();
$video_type = wp_check_filetype( $video_url, wp_get_mime_types() );
$settings = array(
'mimeType' => '',
'posterUrl' => get_header_image(),
'videoUrl' => $video_url,
'width' => absint( $header->width ),
'height' => absint( $header->height ),
'minWidth' => 900,
'minHeight' => 500,
'l10n' => array(
'pause' => __( 'Pause' ),
'play' => __( 'Play' ),
'pauseSpeak' => __( 'Video is paused.' ),
'playSpeak' => __( 'Video is playing.' ),
),
);
if ( preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video_url ) ) {
$settings['mimeType'] = 'video/x-youtube';
} elseif ( ! empty( $video_type['type'] ) ) {
$settings['mimeType'] = $video_type['type'];
}
/**
* Filters header video settings.
*
* @since 4.7.0
*
* @param array $settings An array of header video settings.
*/
return apply_filters( 'header_video_settings', $settings );
}
/**
* Checks whether a custom header is set or not.
*
* @since 4.7.0
*
* @return bool True if a custom header is set. False if not.
*/
function has_custom_header() {
if ( has_header_image() || ( has_header_video() && is_header_video_active() ) ) {
return true;
}
return false;
}
/**
* Checks whether the custom header video is eligible to show on the current page.
*
* @since 4.7.0
*
* @return bool True if the custom header video should be shown. False if not.
*/
function is_header_video_active() {
if ( ! get_theme_support( 'custom-header', 'video' ) ) {
return false;
}
$video_active_cb = get_theme_support( 'custom-header', 'video-active-callback' );
if ( empty( $video_active_cb ) || ! is_callable( $video_active_cb ) ) {
$show_video = true;
} else {
$show_video = call_user_func( $video_active_cb );
}
/**
* Filters whether the custom header video is eligible to show on the current page.
*
* @since 4.7.0
*
* @param bool $show_video Whether the custom header video should be shown. Returns the value
* of the theme setting for the `custom-header`'s `video-active-callback`.
* If no callback is set, the default value is that of `is_front_page()`.
*/
return apply_filters( 'is_header_video_active', $show_video );
}
/**
* Retrieves the markup for a custom header.
*
* The container div will always be returned in the Customizer preview.
*
* @since 4.7.0
*
* @return string The markup for a custom header on success.
*/
function get_custom_header_markup() {
if ( ! has_custom_header() && ! is_customize_preview() ) {
return '';
}
return sprintf(
'<div id="wp-custom-header" class="wp-custom-header">%s</div>',
get_header_image_tag()
);
}
/**
* Prints the markup for a custom header.
*
* A container div will always be printed in the Customizer preview.
*
* @since 4.7.0
*/
function the_custom_header_markup() {
$custom_header = get_custom_header_markup();
if ( empty( $custom_header ) ) {
return;
}
echo $custom_header;
if ( is_header_video_active() && ( has_header_video() || is_customize_preview() ) ) {
wp_enqueue_script( 'wp-custom-header' );
wp_localize_script( 'wp-custom-header', '_wpCustomHeaderSettings', get_header_video_settings() );
}
}
/**
* Retrieves background image for custom background.
*
* @since 3.0.0
*
* @return string
*/
function get_background_image() {
return get_theme_mod( 'background_image', get_theme_support( 'custom-background', 'default-image' ) );
}
/**
* Displays background image path.
*
* @since 3.0.0
*/
function background_image() {
echo get_background_image();
}
/**
* Retrieves value for custom background color.
*
* @since 3.0.0
*
* @return string
*/
function get_background_color() {
return get_theme_mod( 'background_color', get_theme_support( 'custom-background', 'default-color' ) );
}
/**
* Displays background color value.
*
* @since 3.0.0
*/
function background_color() {
echo get_background_color();
}
/**
* Default custom background callback.
*
* @since 3.0.0
*/
function _custom_background_cb() {
// $background is the saved custom image, or the default image.
$background = set_url_scheme( get_background_image() );
/*
* $color is the saved custom color.
* A default has to be specified in style.css. It will not be printed here.
*/
$color = get_background_color();
if ( get_theme_support( 'custom-background', 'default-color' ) === $color ) {
$color = false;
}
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
if ( ! $background && ! $color ) {
if ( is_customize_preview() ) {
printf( '<style%s id="custom-background-css"></style>', $type_attr );
}
return;
}
$style = $color ? 'background-color: ' . maybe_hash_hex_color( $color ) . ';' : '';
if ( $background ) {
$image = ' background-image: url("' . sanitize_url( $background ) . '");';
// Background Position.
$position_x = get_theme_mod( 'background_position_x', get_theme_support( 'custom-background', 'default-position-x' ) );
$position_y = get_theme_mod( 'background_position_y', get_theme_support( 'custom-background', 'default-position-y' ) );
if ( ! in_array( $position_x, array( 'left', 'center', 'right' ), true ) ) {
$position_x = 'left';
}
if ( ! in_array( $position_y, array( 'top', 'center', 'bottom' ), true ) ) {
$position_y = 'top';
}
$position = " background-position: $position_x $position_y;";
// Background Size.
$size = get_theme_mod( 'background_size', get_theme_support( 'custom-background', 'default-size' ) );
if ( ! in_array( $size, array( 'auto', 'contain', 'cover' ), true ) ) {
$size = 'auto';
}
$size = " background-size: $size;";
// Background Repeat.
$repeat = get_theme_mod( 'background_repeat', get_theme_support( 'custom-background', 'default-repeat' ) );
if ( ! in_array( $repeat, array( 'repeat-x', 'repeat-y', 'repeat', 'no-repeat' ), true ) ) {
$repeat = 'repeat';
}
$repeat = " background-repeat: $repeat;";
// Background Scroll.
$attachment = get_theme_mod( 'background_attachment', get_theme_support( 'custom-background', 'default-attachment' ) );
if ( 'fixed' !== $attachment ) {
$attachment = 'scroll';
}
$attachment = " background-attachment: $attachment;";
$style .= $image . $position . $size . $repeat . $attachment;
}
?>
<style<?php echo $type_attr; ?> id="custom-background-css">
body.custom-background { <?php echo trim( $style ); ?> }
</style>
<?php
}
/**
* Renders the Custom CSS style element.
*
* @since 4.7.0
*/
function wp_custom_css_cb() {
$styles = wp_get_custom_css();
if ( $styles || is_customize_preview() ) :
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<style<?php echo $type_attr; ?> id="wp-custom-css">
<?php
// Note that esc_html() cannot be used because `div > span` is not interpreted properly.
echo strip_tags( $styles );
?>
</style>
<?php
endif;
}
/**
* Fetches the `custom_css` post for a given theme.
*
* @since 4.7.0
*
* @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the active theme.
* @return WP_Post|null The custom_css post or null if none exists.
*/
function wp_get_custom_css_post( $stylesheet = '' ) {
if ( empty( $stylesheet ) ) {
$stylesheet = get_stylesheet();
}
$custom_css_query_vars = array(
'post_type' => 'custom_css',
'post_status' => get_post_stati(),
'name' => sanitize_title( $stylesheet ),
'posts_per_page' => 1,
'no_found_rows' => true,
'cache_results' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'lazy_load_term_meta' => false,
);
$post = null;
if ( get_stylesheet() === $stylesheet ) {
$post_id = get_theme_mod( 'custom_css_post_id' );
if ( $post_id > 0 && get_post( $post_id ) ) {
$post = get_post( $post_id );
}
// `-1` indicates no post exists; no query necessary.
if ( ! $post && -1 !== $post_id ) {
$query = new WP_Query( $custom_css_query_vars );
$post = $query->post;
/*
* Cache the lookup. See wp_update_custom_css_post().
* @todo This should get cleared if a custom_css post is added/removed.
*/
set_theme_mod( 'custom_css_post_id', $post ? $post->ID : -1 );
}
} else {
$query = new WP_Query( $custom_css_query_vars );
$post = $query->post;
}
return $post;
}
/**
* Fetches the saved Custom CSS content for rendering.
*
* @since 4.7.0
*
* @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the active theme.
* @return string The Custom CSS Post content.
*/
function wp_get_custom_css( $stylesheet = '' ) {
$css = '';
if ( empty( $stylesheet ) ) {
$stylesheet = get_stylesheet();
}
$post = wp_get_custom_css_post( $stylesheet );
if ( $post ) {
$css = $post->post_content;
}
/**
* Filters the custom CSS output into the head element.
*
* @since 4.7.0
*
* @param string $css CSS pulled in from the Custom CSS post type.
* @param string $stylesheet The theme stylesheet name.
*/
$css = apply_filters( 'wp_get_custom_css', $css, $stylesheet );
return $css;
}
/**
* Updates the `custom_css` post for a given theme.
*
* Inserts a `custom_css` post when one doesn't yet exist.
*
* @since 4.7.0
*
* @param string $css CSS, stored in `post_content`.
* @param array $args {
* Args.
*
* @type string $preprocessed Optional. Pre-processed CSS, stored in `post_content_filtered`.
* Normally empty string.
* @type string $stylesheet Optional. Stylesheet (child theme) to update.
* Defaults to active theme/stylesheet.
* }
* @return WP_Post|WP_Error Post on success, error on failure.
*/
function wp_update_custom_css_post( $css, $args = array() ) {
$args = wp_parse_args(
$args,
array(
'preprocessed' => '',
'stylesheet' => get_stylesheet(),
)
);
$data = array(
'css' => $css,
'preprocessed' => $args['preprocessed'],
);
/**
* Filters the `css` (`post_content`) and `preprocessed` (`post_content_filtered`) args
* for a `custom_css` post being updated.
*
* This filter can be used by plugin that offer CSS pre-processors, to store the original
* pre-processed CSS in `post_content_filtered` and then store processed CSS in `post_content`.
* When used in this way, the `post_content_filtered` should be supplied as the setting value
* instead of `post_content` via a the `customize_value_custom_css` filter, for example:
*
* <code>
* add_filter( 'customize_value_custom_css', function( $value, $setting ) {
* $post = wp_get_custom_css_post( $setting->stylesheet );
* if ( $post && ! empty( $post->post_content_filtered ) ) {
* $css = $post->post_content_filtered;
* }
* return $css;
* }, 10, 2 );
* </code>
*
* @since 4.7.0
* @param array $data {
* Custom CSS data.
*
* @type string $css CSS stored in `post_content`.
* @type string $preprocessed Pre-processed CSS stored in `post_content_filtered`.
* Normally empty string.
* }
* @param array $args {
* The args passed into `wp_update_custom_css_post()` merged with defaults.
*
* @type string $css The original CSS passed in to be updated.
* @type string $preprocessed The original preprocessed CSS passed in to be updated.
* @type string $stylesheet The stylesheet (theme) being updated.
* }
*/
$data = apply_filters( 'update_custom_css_data', $data, array_merge( $args, compact( 'css' ) ) );
$post_data = array(
'post_title' => $args['stylesheet'],
'post_name' => sanitize_title( $args['stylesheet'] ),
'post_type' => 'custom_css',
'post_status' => 'publish',
'post_content' => $data['css'],
'post_content_filtered' => $data['preprocessed'],
);
// Update post if it already exists, otherwise create a new one.
$post = wp_get_custom_css_post( $args['stylesheet'] );
if ( $post ) {
$post_data['ID'] = $post->ID;
$r = wp_update_post( wp_slash( $post_data ), true );
} else {
$r = wp_insert_post( wp_slash( $post_data ), true );
if ( ! is_wp_error( $r ) ) {
if ( get_stylesheet() === $args['stylesheet'] ) {
set_theme_mod( 'custom_css_post_id', $r );
}
// Trigger creation of a revision. This should be removed once #30854 is resolved.
$revisions = wp_get_latest_revision_id_and_total_count( $r );
if ( ! is_wp_error( $revisions ) && 0 === $revisions['count'] ) {
wp_save_post_revision( $r );
}
}
}
if ( is_wp_error( $r ) ) {
return $r;
}
return get_post( $r );
}
/**
* Adds callback for custom TinyMCE editor stylesheets.
*
* The parameter $stylesheet is the name of the stylesheet, relative to
* the theme root. It also accepts an array of stylesheets.
* It is optional and defaults to 'editor-style.css'.
*
* This function automatically adds another stylesheet with -rtl prefix, e.g. editor-style-rtl.css.
* If that file doesn't exist, it is removed before adding the stylesheet(s) to TinyMCE.
* If an array of stylesheets is passed to add_editor_style(),
* RTL is only added for the first stylesheet.
*
* Since version 3.4 the TinyMCE body has .rtl CSS class.
* It is a better option to use that class and add any RTL styles to the main stylesheet.
*
* @since 3.0.0
*
* @global array $editor_styles
*
* @param array|string $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
* Defaults to 'editor-style.css'
*/
function add_editor_style( $stylesheet = 'editor-style.css' ) {
global $editor_styles;
add_theme_support( 'editor-style' );
$editor_styles = (array) $editor_styles;
$stylesheet = (array) $stylesheet;
if ( is_rtl() ) {
$rtl_stylesheet = str_replace( '.css', '-rtl.css', $stylesheet[0] );
$stylesheet[] = $rtl_stylesheet;
}
$editor_styles = array_merge( $editor_styles, $stylesheet );
}
/**
* Removes all visual editor stylesheets.
*
* @since 3.1.0
*
* @global array $editor_styles
*
* @return bool True on success, false if there were no stylesheets to remove.
*/
function remove_editor_styles() {
if ( ! current_theme_supports( 'editor-style' ) ) {
return false;
}
_remove_theme_support( 'editor-style' );
if ( is_admin() ) {
$GLOBALS['editor_styles'] = array();
}
return true;
}
/**
* Retrieves any registered editor stylesheet URLs.
*
* @since 4.0.0
*
* @global array $editor_styles Registered editor stylesheets
*
* @return string[] If registered, a list of editor stylesheet URLs.
*/
function get_editor_stylesheets() {
$stylesheets = array();
// Load editor_style.css if the active theme supports it.
if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
$editor_styles = $GLOBALS['editor_styles'];
$editor_styles = array_unique( array_filter( $editor_styles ) );
$style_uri = get_stylesheet_directory_uri();
$style_dir = get_stylesheet_directory();
// Support externally referenced styles (like, say, fonts).
foreach ( $editor_styles as $key => $file ) {
if ( preg_match( '~^(https?:)?//~', $file ) ) {
$stylesheets[] = sanitize_url( $file );
unset( $editor_styles[ $key ] );
}
}
// Look in a parent theme first, that way child theme CSS overrides.
if ( is_child_theme() ) {
$template_uri = get_template_directory_uri();
$template_dir = get_template_directory();
foreach ( $editor_styles as $key => $file ) {
if ( $file && file_exists( "$template_dir/$file" ) ) {
$stylesheets[] = "$template_uri/$file";
}
}
}
foreach ( $editor_styles as $file ) {
if ( $file && file_exists( "$style_dir/$file" ) ) {
$stylesheets[] = "$style_uri/$file";
}
}
}
/**
* Filters the array of URLs of stylesheets applied to the editor.
*
* @since 4.3.0
*
* @param string[] $stylesheets Array of URLs of stylesheets to be applied to the editor.
*/
return apply_filters( 'editor_stylesheets', $stylesheets );
}
/**
* Expands a theme's starter content configuration using core-provided data.
*
* @since 4.7.0
*
* @return array Array of starter content.
*/
function get_theme_starter_content() {
$theme_support = get_theme_support( 'starter-content' );
if ( is_array( $theme_support ) && ! empty( $theme_support[0] ) && is_array( $theme_support[0] ) ) {
$config = $theme_support[0];
} else {
$config = array();
}
$core_content = array(
'widgets' => array(
'text_business_info' => array(
'text',
array(
'title' => _x( 'Find Us', 'Theme starter content' ),
'text' => implode(
'',
array(
'<strong>' . _x( 'Address', 'Theme starter content' ) . "</strong>\n",
_x( '123 Main Street', 'Theme starter content' ) . "\n",
_x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n",
'<strong>' . _x( 'Hours', 'Theme starter content' ) . "</strong>\n",
_x( 'Monday–Friday: 9:00AM–5:00PM', 'Theme starter content' ) . "\n",
_x( 'Saturday & Sunday: 11:00AM–3:00PM', 'Theme starter content' ),
)
),
'filter' => true,
'visual' => true,
),
),
'text_about' => array(
'text',
array(
'title' => _x( 'About This Site', 'Theme starter content' ),
'text' => _x( 'This may be a good place to introduce yourself and your site or include some credits.', 'Theme starter content' ),
'filter' => true,
'visual' => true,
),
),
'archives' => array(
'archives',
array(
'title' => _x( 'Archives', 'Theme starter content' ),
),
),
'calendar' => array(
'calendar',
array(
'title' => _x( 'Calendar', 'Theme starter content' ),
),
),
'categories' => array(
'categories',
array(
'title' => _x( 'Categories', 'Theme starter content' ),
),
),
'meta' => array(
'meta',
array(
'title' => _x( 'Meta', 'Theme starter content' ),
),
),
'recent-comments' => array(
'recent-comments',
array(
'title' => _x( 'Recent Comments', 'Theme starter content' ),
),
),
'recent-posts' => array(
'recent-posts',
array(
'title' => _x( 'Recent Posts', 'Theme starter content' ),
),
),
'search' => array(
'search',
array(
'title' => _x( 'Search', 'Theme starter content' ),
),
),
),
'nav_menus' => array(
'link_home' => array(
'type' => 'custom',
'title' => _x( 'Home', 'Theme starter content' ),
'url' => home_url( '/' ),
),
'page_home' => array( // Deprecated in favor of 'link_home'.
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{home}}',
),
'page_about' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{about}}',
),
'page_blog' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{blog}}',
),
'page_news' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{news}}',
),
'page_contact' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{contact}}',
),
'link_email' => array(
'title' => _x( 'Email', 'Theme starter content' ),
'url' => 'mailto:wordpress@example.com',
),
'link_facebook' => array(
'title' => _x( 'Facebook', 'Theme starter content' ),
'url' => 'https://www.facebook.com/wordpress',
),
'link_foursquare' => array(
'title' => _x( 'Foursquare', 'Theme starter content' ),
'url' => 'https://foursquare.com/',
),
'link_github' => array(
'title' => _x( 'GitHub', 'Theme starter content' ),
'url' => 'https://github.com/wordpress/',
),
'link_instagram' => array(
'title' => _x( 'Instagram', 'Theme starter content' ),
'url' => 'https://www.instagram.com/explore/tags/wordcamp/',
),
'link_linkedin' => array(
'title' => _x( 'LinkedIn', 'Theme starter content' ),
'url' => 'https://www.linkedin.com/company/1089783',
),
'link_pinterest' => array(
'title' => _x( 'Pinterest', 'Theme starter content' ),
'url' => 'https://www.pinterest.com/',
),
'link_twitter' => array(
'title' => _x( 'Twitter', 'Theme starter content' ),
'url' => 'https://twitter.com/wordpress',
),
'link_yelp' => array(
'title' => _x( 'Yelp', 'Theme starter content' ),
'url' => 'https://www.yelp.com',
),
'link_youtube' => array(
'title' => _x( 'YouTube', 'Theme starter content' ),
'url' => 'https://www.youtube.com/channel/UCdof4Ju7amm1chz1gi1T2ZA',
),
),
'posts' => array(
'home' => array(
'post_type' => 'page',
'post_title' => _x( 'Home', 'Theme starter content' ),
'post_content' => sprintf(
"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
_x( 'Welcome to your site! This is your homepage, which is what most visitors will see when they come to your site for the first time.', 'Theme starter content' )
),
),
'about' => array(
'post_type' => 'page',
'post_title' => _x( 'About', 'Theme starter content' ),
'post_content' => sprintf(
"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
_x( 'You might be an artist who would like to introduce yourself and your work here or maybe you are a business with a mission to describe.', 'Theme starter content' )
),
),
'contact' => array(
'post_type' => 'page',
'post_title' => _x( 'Contact', 'Theme starter content' ),
'post_content' => sprintf(
"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
_x( 'This is a page with some basic contact information, such as an address and phone number. You might also try a plugin to add a contact form.', 'Theme starter content' )
),
),
'blog' => array(
'post_type' => 'page',
'post_title' => _x( 'Blog', 'Theme starter content' ),
),
'news' => array(
'post_type' => 'page',
'post_title' => _x( 'News', 'Theme starter content' ),
),
'homepage-section' => array(
'post_type' => 'page',
'post_title' => _x( 'A homepage section', 'Theme starter content' ),
'post_content' => sprintf(
"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
_x( 'This is an example of a homepage section. Homepage sections can be any page other than the homepage itself, including the page that shows your latest blog posts.', 'Theme starter content' )
),
),
),
);
$content = array();
foreach ( $config as $type => $args ) {
switch ( $type ) {
// Use options and theme_mods as-is.
case 'options':
case 'theme_mods':
$content[ $type ] = $config[ $type ];
break;
// Widgets are grouped into sidebars.
case 'widgets':
foreach ( $config[ $type ] as $sidebar_id => $widgets ) {
foreach ( $widgets as $id => $widget ) {
if ( is_array( $widget ) ) {
// Item extends core content.
if ( ! empty( $core_content[ $type ][ $id ] ) ) {
$widget = array(
$core_content[ $type ][ $id ][0],
array_merge( $core_content[ $type ][ $id ][1], $widget ),
);
}
$content[ $type ][ $sidebar_id ][] = $widget;
} elseif ( is_string( $widget )
&& ! empty( $core_content[ $type ] )
&& ! empty( $core_content[ $type ][ $widget ] )
) {
$content[ $type ][ $sidebar_id ][] = $core_content[ $type ][ $widget ];
}
}
}
break;
// And nav menu items are grouped into nav menus.
case 'nav_menus':
foreach ( $config[ $type ] as $nav_menu_location => $nav_menu ) {
// Ensure nav menus get a name.
if ( empty( $nav_menu['name'] ) ) {
$nav_menu['name'] = $nav_menu_location;
}
$content[ $type ][ $nav_menu_location ]['name'] = $nav_menu['name'];
foreach ( $nav_menu['items'] as $id => $nav_menu_item ) {
if ( is_array( $nav_menu_item ) ) {
// Item extends core content.
if ( ! empty( $core_content[ $type ][ $id ] ) ) {
$nav_menu_item = array_merge( $core_content[ $type ][ $id ], $nav_menu_item );
}
$content[ $type ][ $nav_menu_location ]['items'][] = $nav_menu_item;
} elseif ( is_string( $nav_menu_item )
&& ! empty( $core_content[ $type ] )
&& ! empty( $core_content[ $type ][ $nav_menu_item ] )
) {
$content[ $type ][ $nav_menu_location ]['items'][] = $core_content[ $type ][ $nav_menu_item ];
}
}
}
break;
// Attachments are posts but have special treatment.
case 'attachments':
foreach ( $config[ $type ] as $id => $item ) {
if ( ! empty( $item['file'] ) ) {
$content[ $type ][ $id ] = $item;
}
}
break;
/*
* All that's left now are posts (besides attachments).
* Not a default case for the sake of clarity and future work.
*/
case 'posts':
foreach ( $config[ $type ] as $id => $item ) {
if ( is_array( $item ) ) {
// Item extends core content.
if ( ! empty( $core_content[ $type ][ $id ] ) ) {
$item = array_merge( $core_content[ $type ][ $id ], $item );
}
// Enforce a subset of fields.
$content[ $type ][ $id ] = wp_array_slice_assoc(
$item,
array(
'post_type',
'post_title',
'post_excerpt',
'post_name',
'post_content',
'menu_order',
'comment_status',
'thumbnail',
'template',
)
);
} elseif ( is_string( $item ) && ! empty( $core_content[ $type ][ $item ] ) ) {
$content[ $type ][ $item ] = $core_content[ $type ][ $item ];
}
}
break;
}
}
/**
* Filters the expanded array of starter content.
*
* @since 4.7.0
*
* @param array $content Array of starter content.
* @param array $config Array of theme-specific starter content configuration.
*/
return apply_filters( 'get_theme_starter_content', $content, $config );
}
/**
* Registers theme support for a given feature.
*
* Must be called in the theme's functions.php file to work.
* If attached to a hook, it must be {@see 'after_setup_theme'}.
* The {@see 'init'} hook may be too late for some features.
*
* Example usage:
*
* add_theme_support( 'title-tag' );
* add_theme_support( 'custom-logo', array(
* 'height' => 480,
* 'width' => 720,
* ) );
*
* @since 2.9.0
* @since 3.4.0 The `custom-header-uploads` feature was deprecated.
* @since 3.6.0 The `html5` feature was added.
* @since 3.6.1 The `html5` feature requires an array of types to be passed. Defaults to
* 'comment-list', 'comment-form', 'search-form' for backward compatibility.
* @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'.
* @since 4.1.0 The `title-tag` feature was added.
* @since 4.5.0 The `customize-selective-refresh-widgets` feature was added.
* @since 4.7.0 The `starter-content` feature was added.
* @since 5.0.0 The `responsive-embeds`, `align-wide`, `dark-editor-style`, `disable-custom-colors`,
* `disable-custom-font-sizes`, `editor-color-palette`, `editor-font-sizes`,
* `editor-styles`, and `wp-block-styles` features were added.
* @since 5.3.0 The `html5` feature now also accepts 'script' and 'style'.
* @since 5.3.0 Formalized the existing and already documented `...$args` parameter
* by adding it to the function signature.
* @since 5.4.0 The `disable-custom-gradients` feature limits to default gradients or gradients added
* through `editor-gradient-presets` theme support.
* @since 5.5.0 The `core-block-patterns` feature was added and is enabled by default.
* @since 5.5.0 The `custom-logo` feature now also accepts 'unlink-homepage-logo'.
* @since 5.6.0 The `post-formats` feature warns if no array is passed as the second parameter.
* @since 5.8.0 The `widgets-block-editor` feature enables the Widgets block editor.
* @since 5.8.0 The `block-templates` feature indicates whether a theme uses block-based templates.
* @since 6.0.0 The `html5` feature warns if no array is passed as the second parameter.
* @since 6.1.0 The `block-template-parts` feature allows to edit any reusable template part from site editor.
* @since 6.1.0 The `disable-layout-styles` feature disables the default layout styles.
* @since 6.3.0 The `link-color` feature allows to enable the link color setting.
* @since 6.3.0 The `border` feature allows themes without theme.json to add border styles to blocks.
* @since 6.5.0 The `appearance-tools` feature enables a few design tools for blocks,
* see `WP_Theme_JSON::APPEARANCE_TOOLS_OPT_INS` for a complete list.
* @since 6.6.0 The `editor-spacing-sizes` feature was added.
*
* @global array $_wp_theme_features
*
* @param string $feature The feature being added. Likely core values include:
* - 'admin-bar'
* - 'align-wide'
* - 'appearance-tools'
* - 'automatic-feed-links'
* - 'block-templates'
* - 'block-template-parts'
* - 'border'
* - 'core-block-patterns'
* - 'custom-background'
* - 'custom-header'
* - 'custom-line-height'
* - 'custom-logo'
* - 'customize-selective-refresh-widgets'
* - 'custom-spacing'
* - 'custom-units'
* - 'dark-editor-style'
* - 'disable-custom-colors'
* - 'disable-custom-font-sizes'
* - 'disable-custom-gradients'
* - 'disable-layout-styles'
* - 'editor-color-palette'
* - 'editor-gradient-presets'
* - 'editor-font-sizes'
* - 'editor-spacing-sizes'
* - 'editor-styles'
* - 'featured-content'
* - 'html5'
* - 'link-color'
* - 'menus'
* - 'post-formats'
* - 'post-thumbnails'
* - 'responsive-embeds'
* - 'starter-content'
* - 'title-tag'
* - 'widgets'
* - 'widgets-block-editor'
* - 'wp-block-styles'
* @param mixed ...$args Optional extra arguments to pass along with certain features.
* @return void|false Void on success, false on failure.
*/
function add_theme_support( $feature, ...$args ) {
global $_wp_theme_features;
if ( ! $args ) {
$args = true;
}
switch ( $feature ) {
case 'post-thumbnails':
// All post types are already supported.
if ( true === get_theme_support( 'post-thumbnails' ) ) {
return;
}
/*
* Merge post types with any that already declared their support
* for post thumbnails.
*/
if ( isset( $args[0] ) && is_array( $args[0] ) && isset( $_wp_theme_features['post-thumbnails'] ) ) {
$args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) );
}
break;
case 'post-formats':
if ( isset( $args[0] ) && is_array( $args[0] ) ) {
$post_formats = get_post_format_slugs();
unset( $post_formats['standard'] );
$args[0] = array_intersect( $args[0], array_keys( $post_formats ) );
} else {
_doing_it_wrong(
"add_theme_support( 'post-formats' )",
__( 'You need to pass an array of post formats.' ),
'5.6.0'
);
return false;
}
break;
case 'html5':
// You can't just pass 'html5', you need to pass an array of types.
if ( empty( $args[0] ) || ! is_array( $args[0] ) ) {
_doing_it_wrong(
"add_theme_support( 'html5' )",
__( 'You need to pass an array of types.' ),
'3.6.1'
);
if ( ! empty( $args[0] ) && ! is_array( $args[0] ) ) {
return false;
}
// Build an array of types for back-compat.
$args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) );
}
// Calling 'html5' again merges, rather than overwrites.
if ( isset( $_wp_theme_features['html5'] ) ) {
$args[0] = array_merge( $_wp_theme_features['html5'][0], $args[0] );
}
break;
case 'custom-logo':
if ( true === $args ) {
$args = array( 0 => array() );
}
$defaults = array(
'width' => null,
'height' => null,
'flex-width' => false,
'flex-height' => false,
'header-text' => '',
'unlink-homepage-logo' => false,
);
$args[0] = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults );
// Allow full flexibility if no size is specified.
if ( is_null( $args[0]['width'] ) && is_null( $args[0]['height'] ) ) {
$args[0]['flex-width'] = true;
$args[0]['flex-height'] = true;
}
break;
case 'custom-header-uploads':
return add_theme_support( 'custom-header', array( 'uploads' => true ) );
case 'custom-header':
if ( true === $args ) {
$args = array( 0 => array() );
}
$defaults = array(
'default-image' => '',
'random-default' => false,
'width' => 0,
'height' => 0,
'flex-height' => false,
'flex-width' => false,
'default-text-color' => '',
'header-text' => true,
'uploads' => true,
'wp-head-callback' => '',
'admin-head-callback' => '',
'admin-preview-callback' => '',
'video' => false,
'video-active-callback' => 'is_front_page',
);
$jit = isset( $args[0]['__jit'] );
unset( $args[0]['__jit'] );
/*
* Merge in data from previous add_theme_support() calls.
* The first value registered wins. (A child theme is set up first.)
*/
if ( isset( $_wp_theme_features['custom-header'] ) ) {
$args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] );
}
/*
* Load in the defaults at the end, as we need to insure first one wins.
* This will cause all constants to be defined, as each arg will then be set to the default.
*/
if ( $jit ) {
$args[0] = wp_parse_args( $args[0], $defaults );
}
/*
* If a constant was defined, use that value. Otherwise, define the constant to ensure
* the constant is always accurate (and is not defined later, overriding our value).
* As stated above, the first value wins.
* Once we get to wp_loaded (just-in-time), define any constants we haven't already.
* Constants should be avoided. Don't reference them. This is just for backward compatibility.
*/
if ( defined( 'NO_HEADER_TEXT' ) ) {
$args[0]['header-text'] = ! NO_HEADER_TEXT;
} elseif ( isset( $args[0]['header-text'] ) ) {
define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
}
if ( defined( 'HEADER_IMAGE_WIDTH' ) ) {
$args[0]['width'] = (int) HEADER_IMAGE_WIDTH;
} elseif ( isset( $args[0]['width'] ) ) {
define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] );
}
if ( defined( 'HEADER_IMAGE_HEIGHT' ) ) {
$args[0]['height'] = (int) HEADER_IMAGE_HEIGHT;
} elseif ( isset( $args[0]['height'] ) ) {
define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] );
}
if ( defined( 'HEADER_TEXTCOLOR' ) ) {
$args[0]['default-text-color'] = HEADER_TEXTCOLOR;
} elseif ( isset( $args[0]['default-text-color'] ) ) {
define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] );
}
if ( defined( 'HEADER_IMAGE' ) ) {
$args[0]['default-image'] = HEADER_IMAGE;
} elseif ( isset( $args[0]['default-image'] ) ) {
define( 'HEADER_IMAGE', $args[0]['default-image'] );
}
if ( $jit && ! empty( $args[0]['default-image'] ) ) {
$args[0]['random-default'] = false;
}
/*
* If headers are supported, and we still don't have a defined width or height,
* we have implicit flex sizes.
*/
if ( $jit ) {
if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) ) {
$args[0]['flex-width'] = true;
}
if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) ) {
$args[0]['flex-height'] = true;
}
}
break;
case 'custom-background':
if ( true === $args ) {
$args = array( 0 => array() );
}
$defaults = array(
'default-image' => '',
'default-preset' => 'default',
'default-position-x' => 'left',
'default-position-y' => 'top',
'default-size' => 'auto',
'default-repeat' => 'repeat',
'default-attachment' => 'scroll',
'default-color' => '',
'wp-head-callback' => '_custom_background_cb',
'admin-head-callback' => '',
'admin-preview-callback' => '',
);
$jit = isset( $args[0]['__jit'] );
unset( $args[0]['__jit'] );
// Merge in data from previous add_theme_support() calls. The first value registered wins.
if ( isset( $_wp_theme_features['custom-background'] ) ) {
$args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] );
}
if ( $jit ) {
$args[0] = wp_parse_args( $args[0], $defaults );
}
if ( defined( 'BACKGROUND_COLOR' ) ) {
$args[0]['default-color'] = BACKGROUND_COLOR;
} elseif ( isset( $args[0]['default-color'] ) || $jit ) {
define( 'BACKGROUND_COLOR', $args[0]['default-color'] );
}
if ( defined( 'BACKGROUND_IMAGE' ) ) {
$args[0]['default-image'] = BACKGROUND_IMAGE;
} elseif ( isset( $args[0]['default-image'] ) || $jit ) {
define( 'BACKGROUND_IMAGE', $args[0]['default-image'] );
}
break;
// Ensure that 'title-tag' is accessible in the admin.
case 'title-tag':
// Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php.
if ( did_action( 'wp_loaded' ) ) {
_doing_it_wrong(
"add_theme_support( 'title-tag' )",
sprintf(
/* translators: 1: title-tag, 2: wp_loaded */
__( 'Theme support for %1$s should be registered before the %2$s hook.' ),
'<code>title-tag</code>',
'<code>wp_loaded</code>'
),
'4.1.0'
);
return false;
}
}
$_wp_theme_features[ $feature ] = $args;
}
/**
* Registers the internal custom header and background routines.
*
* @since 3.4.0
* @access private
*
* @global Custom_Image_Header $custom_image_header
* @global Custom_Background $custom_background
*/
function _custom_header_background_just_in_time() {
global $custom_image_header, $custom_background;
if ( current_theme_supports( 'custom-header' ) ) {
// In case any constants were defined after an add_custom_image_header() call, re-run.
add_theme_support( 'custom-header', array( '__jit' => true ) );
$args = get_theme_support( 'custom-header' );
if ( $args[0]['wp-head-callback'] ) {
add_action( 'wp_head', $args[0]['wp-head-callback'] );
}
if ( is_admin() ) {
require_once ABSPATH . 'wp-admin/includes/class-custom-image-header.php';
$custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
}
}
if ( current_theme_supports( 'custom-background' ) ) {
// In case any constants were defined after an add_custom_background() call, re-run.
add_theme_support( 'custom-background', array( '__jit' => true ) );
$args = get_theme_support( 'custom-background' );
add_action( 'wp_head', $args[0]['wp-head-callback'] );
if ( is_admin() ) {
require_once ABSPATH . 'wp-admin/includes/class-custom-background.php';
$custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
}
}
}
/**
* Adds CSS to hide header text for custom logo, based on Customizer setting.
*
* @since 4.5.0
* @access private
*/
function _custom_logo_header_styles() {
if ( ! current_theme_supports( 'custom-header', 'header-text' )
&& get_theme_support( 'custom-logo', 'header-text' )
&& ! get_theme_mod( 'header_text', true )
) {
$classes = (array) get_theme_support( 'custom-logo', 'header-text' );
$classes = array_map( 'sanitize_html_class', $classes );
$classes = '.' . implode( ', .', $classes );
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<!-- Custom Logo: hide header text -->
<style id="custom-logo-css"<?php echo $type_attr; ?>>
<?php echo $classes; ?> {
position: absolute;
clip-path: inset(50%);
}
</style>
<?php
}
}
/**
* Gets the theme support arguments passed when registering that support.
*
* Example usage:
*
* get_theme_support( 'custom-logo' );
* get_theme_support( 'custom-header', 'width' );
*
* @since 3.1.0
* @since 5.3.0 Formalized the existing and already documented `...$args` parameter
* by adding it to the function signature.
*
* @global array $_wp_theme_features
*
* @param string $feature The feature to check. See add_theme_support() for the list
* of possible values.
* @param mixed ...$args Optional extra arguments to be checked against certain features.
* @return mixed The array of extra arguments or the value for the registered feature.
*/
function get_theme_support( $feature, ...$args ) {
global $_wp_theme_features;
if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
return false;
}
if ( ! $args ) {
return $_wp_theme_features[ $feature ];
}
switch ( $feature ) {
case 'custom-logo':
case 'custom-header':
case 'custom-background':
if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) ) {
return $_wp_theme_features[ $feature ][0][ $args[0] ];
}
return false;
default:
return $_wp_theme_features[ $feature ];
}
}
/**
* Allows a theme to de-register its support of a certain feature
*
* Should be called in the theme's functions.php file. Generally would
* be used for child themes to override support from the parent theme.
*
* @since 3.0.0
*
* @see add_theme_support()
*
* @param string $feature The feature being removed. See add_theme_support() for the list
* of possible values.
* @return bool|void Whether feature was removed.
*/
function remove_theme_support( $feature ) {
// Do not remove internal registrations that are not used directly by themes.
if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ), true ) ) {
return false;
}
return _remove_theme_support( $feature );
}
/**
* Do not use. Removes theme support internally without knowledge of those not used
* by themes directly.
*
* @access private
* @since 3.1.0
* @global array $_wp_theme_features
* @global Custom_Image_Header $custom_image_header
* @global Custom_Background $custom_background
*
* @param string $feature The feature being removed. See add_theme_support() for the list
* of possible values.
* @return bool True if support was removed, false if the feature was not registered.
*/
function _remove_theme_support( $feature ) {
global $_wp_theme_features;
switch ( $feature ) {
case 'custom-header-uploads':
if ( ! isset( $_wp_theme_features['custom-header'] ) ) {
return false;
}
add_theme_support( 'custom-header', array( 'uploads' => false ) );
return; // Do not continue - custom-header-uploads no longer exists.
}
if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
return false;
}
switch ( $feature ) {
case 'custom-header':
if ( ! did_action( 'wp_loaded' ) ) {
break;
}
$support = get_theme_support( 'custom-header' );
if ( isset( $support[0]['wp-head-callback'] ) ) {
remove_action( 'wp_head', $support[0]['wp-head-callback'] );
}
if ( isset( $GLOBALS['custom_image_header'] ) ) {
remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
unset( $GLOBALS['custom_image_header'] );
}
break;
case 'custom-background':
if ( ! did_action( 'wp_loaded' ) ) {
break;
}
$support = get_theme_support( 'custom-background' );
if ( isset( $support[0]['wp-head-callback'] ) ) {
remove_action( 'wp_head', $support[0]['wp-head-callback'] );
}
remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
unset( $GLOBALS['custom_background'] );
break;
}
unset( $_wp_theme_features[ $feature ] );
return true;
}
/**
* Checks a theme's support for a given feature.
*
* Example usage:
*
* current_theme_supports( 'custom-logo' );
* current_theme_supports( 'html5', 'comment-form' );
*
* @since 2.9.0
* @since 5.3.0 Formalized the existing and already documented `...$args` parameter
* by adding it to the function signature.
*
* @global array $_wp_theme_features
*
* @param string $feature The feature being checked. See add_theme_support() for the list
* of possible values.
* @param mixed ...$args Optional extra arguments to be checked against certain features.
* @return bool True if the active theme supports the feature, false otherwise.
*/
function current_theme_supports( $feature, ...$args ) {
global $_wp_theme_features;
if ( 'custom-header-uploads' === $feature ) {
return current_theme_supports( 'custom-header', 'uploads' );
}
if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
return false;
}
// If no args passed then no extra checks need to be performed.
if ( ! $args ) {
/** This filter is documented in wp-includes/theme.php */
return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
switch ( $feature ) {
case 'post-thumbnails':
/*
* post-thumbnails can be registered for only certain content/post types
* by passing an array of types to add_theme_support().
* If no array was passed, then any type is accepted.
*/
if ( true === $_wp_theme_features[ $feature ] ) { // Registered for all types.
return true;
}
$content_type = $args[0];
return in_array( $content_type, $_wp_theme_features[ $feature ][0], true );
case 'html5':
case 'post-formats':
/*
* Specific post formats can be registered by passing an array of types
* to add_theme_support().
*
* Specific areas of HTML5 support *must* be passed via an array to add_theme_support().
*/
$type = $args[0];
return in_array( $type, $_wp_theme_features[ $feature ][0], true );
case 'custom-logo':
case 'custom-header':
case 'custom-background':
// Specific capabilities can be registered by passing an array to add_theme_support().
return ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) && $_wp_theme_features[ $feature ][0][ $args[0] ] );
}
/**
* Filters whether the active theme supports a specific feature.
*
* The dynamic portion of the hook name, `$feature`, refers to the specific
* theme feature. See add_theme_support() for the list of possible values.
*
* @since 3.4.0
*
* @param bool $supports Whether the active theme supports the given feature. Default true.
* @param array $args Array of arguments for the feature.
* @param string $feature The theme feature.
*/
return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
/**
* Checks a theme's support for a given feature before loading the functions which implement it.
*
* @since 2.9.0
*
* @param string $feature The feature being checked. See add_theme_support() for the list
* of possible values.
* @param string $file Path to the file.
* @return bool True if the active theme supports the supplied feature, false otherwise.
*/
function require_if_theme_supports( $feature, $file ) {
if ( current_theme_supports( $feature ) ) {
require $file;
return true;
}
return false;
}
/**
* Registers a theme feature for use in add_theme_support().
*
* This does not indicate that the active theme supports the feature, it only describes
* the feature's supported options.
*
* @since 5.5.0
*
* @see add_theme_support()
*
* @global array $_wp_registered_theme_features
*
* @param string $feature The name uniquely identifying the feature. See add_theme_support()
* for the list of possible values.
* @param array $args {
* Data used to describe the theme.
*
* @type string $type The type of data associated with this feature.
* Valid values are 'string', 'boolean', 'integer',
* 'number', 'array', and 'object'. Defaults to 'boolean'.
* @type bool $variadic Does this feature utilize the variadic support
* of add_theme_support(), or are all arguments specified
* as the second parameter. Must be used with the "array" type.
* @type string $description A short description of the feature. Included in
* the Themes REST API schema. Intended for developers.
* @type bool|array $show_in_rest {
* Whether this feature should be included in the Themes REST API endpoint.
* Defaults to not being included. When registering an 'array' or 'object' type,
* this argument must be an array with the 'schema' key.
*
* @type array $schema Specifies the JSON Schema definition describing
* the feature. If any objects in the schema do not include
* the 'additionalProperties' keyword, it is set to false.
* @type string $name An alternate name to be used as the property name
* in the REST API.
* @type callable $prepare_callback A function used to format the theme support in the REST API.
* Receives the raw theme support value.
* }
* }
* @return true|WP_Error True if the theme feature was successfully registered, a WP_Error object if not.
*/
function register_theme_feature( $feature, $args = array() ) {
global $_wp_registered_theme_features;
if ( ! is_array( $_wp_registered_theme_features ) ) {
$_wp_registered_theme_features = array();
}
$defaults = array(
'type' => 'boolean',
'variadic' => false,
'description' => '',
'show_in_rest' => false,
);
$args = wp_parse_args( $args, $defaults );
if ( true === $args['show_in_rest'] ) {
$args['show_in_rest'] = array();
}
if ( is_array( $args['show_in_rest'] ) ) {
$args['show_in_rest'] = wp_parse_args(
$args['show_in_rest'],
array(
'schema' => array(),
'name' => $feature,
'prepare_callback' => null,
)
);
}
if ( ! in_array( $args['type'], array( 'string', 'boolean', 'integer', 'number', 'array', 'object' ), true ) ) {
return new WP_Error(
'invalid_type',
__( 'The feature "type" is not valid JSON Schema type.' )
);
}
if ( true === $args['variadic'] && 'array' !== $args['type'] ) {
return new WP_Error(
'variadic_must_be_array',
__( 'When registering a "variadic" theme feature, the "type" must be an "array".' )
);
}
if ( false !== $args['show_in_rest'] && in_array( $args['type'], array( 'array', 'object' ), true ) ) {
if ( ! is_array( $args['show_in_rest'] ) || empty( $args['show_in_rest']['schema'] ) ) {
return new WP_Error(
'missing_schema',
__( 'When registering an "array" or "object" feature to show in the REST API, the feature\'s schema must also be defined.' )
);
}
if ( 'array' === $args['type'] && ! isset( $args['show_in_rest']['schema']['items'] ) ) {
return new WP_Error(
'missing_schema_items',
__( 'When registering an "array" feature, the feature\'s schema must include the "items" keyword.' )
);
}
if ( 'object' === $args['type'] && ! isset( $args['show_in_rest']['schema']['properties'] ) ) {
return new WP_Error(
'missing_schema_properties',
__( 'When registering an "object" feature, the feature\'s schema must include the "properties" keyword.' )
);
}
}
if ( is_array( $args['show_in_rest'] ) ) {
if ( isset( $args['show_in_rest']['prepare_callback'] )
&& ! is_callable( $args['show_in_rest']['prepare_callback'] )
) {
return new WP_Error(
'invalid_rest_prepare_callback',
sprintf(
/* translators: %s: prepare_callback */
__( 'The "%s" must be a callable function.' ),
'prepare_callback'
)
);
}
$args['show_in_rest']['schema'] = wp_parse_args(
$args['show_in_rest']['schema'],
array(
'description' => $args['description'],
'type' => $args['type'],
'default' => false,
)
);
if ( is_bool( $args['show_in_rest']['schema']['default'] )
&& ! in_array( 'boolean', (array) $args['show_in_rest']['schema']['type'], true )
) {
// Automatically include the "boolean" type when the default value is a boolean.
$args['show_in_rest']['schema']['type'] = (array) $args['show_in_rest']['schema']['type'];
array_unshift( $args['show_in_rest']['schema']['type'], 'boolean' );
}
$args['show_in_rest']['schema'] = rest_default_additional_properties_to_false( $args['show_in_rest']['schema'] );
}
$_wp_registered_theme_features[ $feature ] = $args;
return true;
}
/**
* Gets the list of registered theme features.
*
* @since 5.5.0
*
* @global array $_wp_registered_theme_features
*
* @return array[] List of theme features, keyed by their name.
*/
function get_registered_theme_features() {
global $_wp_registered_theme_features;
if ( ! is_array( $_wp_registered_theme_features ) ) {
return array();
}
return $_wp_registered_theme_features;
}
/**
* Gets the registration config for a theme feature.
*
* @since 5.5.0
*
* @global array $_wp_registered_theme_features
*
* @param string $feature The feature name. See add_theme_support() for the list
* of possible values.
* @return array|null The registration args, or null if the feature was not registered.
*/
function get_registered_theme_feature( $feature ) {
global $_wp_registered_theme_features;
if ( ! is_array( $_wp_registered_theme_features ) ) {
return null;
}
return isset( $_wp_registered_theme_features[ $feature ] ) ? $_wp_registered_theme_features[ $feature ] : null;
}
/**
* Checks an attachment being deleted to see if it's a header or background image.
*
* If true it removes the theme modification which would be pointing at the deleted
* attachment.
*
* @access private
* @since 3.0.0
* @since 4.3.0 Also removes `header_image_data`.
* @since 4.5.0 Also removes custom logo theme mods.
* @since 6.6.0 Also removes `site_logo` option set by the site logo block.
*
* @param int $id The attachment ID.
*/
function _delete_attachment_theme_mod( $id ) {
$attachment_image = wp_get_attachment_url( $id );
$header_image = get_header_image();
$background_image = get_background_image();
$custom_logo_id = (int) get_theme_mod( 'custom_logo' );
$site_logo_id = (int) get_option( 'site_logo' );
if ( $custom_logo_id && $custom_logo_id === $id ) {
remove_theme_mod( 'custom_logo' );
remove_theme_mod( 'header_text' );
}
if ( $site_logo_id && $site_logo_id === $id ) {
delete_option( 'site_logo' );
}
if ( $header_image && $header_image === $attachment_image ) {
remove_theme_mod( 'header_image' );
remove_theme_mod( 'header_image_data' );
}
if ( $background_image && $background_image === $attachment_image ) {
remove_theme_mod( 'background_image' );
}
}
/**
* Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load.
*
* See {@see 'after_switch_theme'}.
*
* @since 3.3.0
*/
function check_theme_switched() {
$stylesheet = get_option( 'theme_switched' );
if ( $stylesheet ) {
$old_theme = wp_get_theme( $stylesheet );
// Prevent widget & menu mapping from running since Customizer already called it up front.
if ( get_option( 'theme_switched_via_customizer' ) ) {
remove_action( 'after_switch_theme', '_wp_menus_changed' );
remove_action( 'after_switch_theme', '_wp_sidebars_changed' );
update_option( 'theme_switched_via_customizer', false );
}
if ( $old_theme->exists() ) {
/**
* Fires on the next WP load after the theme has been switched.
*
* The parameters differ according to whether the old theme exists or not.
* If the old theme is missing, the old name will instead be the slug
* of the old theme.
*
* See {@see 'switch_theme'}.
*
* @since 3.3.0
*
* @param string $old_name Old theme name.
* @param WP_Theme $old_theme WP_Theme instance of the old theme.
*/
do_action( 'after_switch_theme', $old_theme->get( 'Name' ), $old_theme );
} else {
/** This action is documented in wp-includes/theme.php */
do_action( 'after_switch_theme', $stylesheet, $old_theme );
}
flush_rewrite_rules();
update_option( 'theme_switched', false );
}
}
/**
* Includes and instantiates the WP_Customize_Manager class.
*
* Loads the Customizer at plugins_loaded when accessing the customize.php admin
* page or when any request includes a wp_customize=on param or a customize_changeset
* param (a UUID). This param is a signal for whether to bootstrap the Customizer when
* WordPress is loading, especially in the Customizer preview
* or when making Customizer Ajax requests for widgets or menus.
*
* @since 3.4.0
*
* @global WP_Customize_Manager $wp_customize
*/
function _wp_customize_include() {
$is_customize_admin_page = ( is_admin() && 'customize.php' === basename( $_SERVER['PHP_SELF'] ) );
$should_include = (
$is_customize_admin_page
||
( isset( $_REQUEST['wp_customize'] ) && 'on' === $_REQUEST['wp_customize'] )
||
( ! empty( $_GET['customize_changeset_uuid'] ) || ! empty( $_POST['customize_changeset_uuid'] ) )
);
if ( ! $should_include ) {
return;
}
/*
* Note that wp_unslash() is not being used on the input vars because it is
* called before wp_magic_quotes() gets called. Besides this fact, none of
* the values should contain any characters needing slashes anyway.
*/
$keys = array(
'changeset_uuid',
'customize_changeset_uuid',
'customize_theme',
'theme',
'customize_messenger_channel',
'customize_autosaved',
);
$input_vars = array_merge(
wp_array_slice_assoc( $_GET, $keys ),
wp_array_slice_assoc( $_POST, $keys )
);
$theme = null;
$autosaved = null;
$messenger_channel = null;
/*
* Value false indicates UUID should be determined after_setup_theme
* to either re-use existing saved changeset or else generate a new UUID if none exists.
*/
$changeset_uuid = false;
/*
* Set initially to false since defaults to true for back-compat;
* can be overridden via the customize_changeset_branching filter.
*/
$branching = false;
if ( $is_customize_admin_page && isset( $input_vars['changeset_uuid'] ) ) {
$changeset_uuid = sanitize_key( $input_vars['changeset_uuid'] );
} elseif ( ! empty( $input_vars['customize_changeset_uuid'] ) ) {
$changeset_uuid = sanitize_key( $input_vars['customize_changeset_uuid'] );
}
// Note that theme will be sanitized via WP_Theme.
if ( $is_customize_admin_page && isset( $input_vars['theme'] ) ) {
$theme = $input_vars['theme'];
} elseif ( isset( $input_vars['customize_theme'] ) ) {
$theme = $input_vars['customize_theme'];
}
if ( ! empty( $input_vars['customize_autosaved'] ) ) {
$autosaved = true;
}
if ( isset( $input_vars['customize_messenger_channel'] ) ) {
$messenger_channel = sanitize_key( $input_vars['customize_messenger_channel'] );
}
/*
* Note that settings must be previewed even outside the customizer preview
* and also in the customizer pane itself. This is to enable loading an existing
* changeset into the customizer. Previewing the settings only has to be prevented
* here in the case of a customize_save action because this will cause WP to think
* there is nothing changed that needs to be saved.
*/
$is_customize_save_action = (
wp_doing_ajax()
&&
isset( $_REQUEST['action'] )
&&
'customize_save' === wp_unslash( $_REQUEST['action'] )
);
$settings_previewed = ! $is_customize_save_action;
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
$GLOBALS['wp_customize'] = new WP_Customize_Manager(
compact(
'changeset_uuid',
'theme',
'messenger_channel',
'settings_previewed',
'autosaved',
'branching'
)
);
}
/**
* Publishes a snapshot's changes.
*
* @since 4.7.0
* @access private
*
* @global WP_Customize_Manager $wp_customize Customizer instance.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $changeset_post Changeset post object.
*/
function _wp_customize_publish_changeset( $new_status, $old_status, $changeset_post ) {
global $wp_customize;
$is_publishing_changeset = (
'customize_changeset' === $changeset_post->post_type
&&
'publish' === $new_status
&&
'publish' !== $old_status
);
if ( ! $is_publishing_changeset ) {
return;
}
if ( empty( $wp_customize ) ) {
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
$wp_customize = new WP_Customize_Manager(
array(
'changeset_uuid' => $changeset_post->post_name,
'settings_previewed' => false,
)
);
}
if ( ! did_action( 'customize_register' ) ) {
/*
* When running from CLI or Cron, the customize_register action will need
* to be triggered in order for core, themes, and plugins to register their
* settings. Normally core will add_action( 'customize_register' ) at
* priority 10 to register the core settings, and if any themes/plugins
* also add_action( 'customize_register' ) at the same priority, they
* will have a $wp_customize with those settings registered since they
* call add_action() afterward, normally. However, when manually doing
* the customize_register action after the setup_theme, then the order
* will be reversed for two actions added at priority 10, resulting in
* the core settings no longer being available as expected to themes/plugins.
* So the following manually calls the method that registers the core
* settings up front before doing the action.
*/
remove_action( 'customize_register', array( $wp_customize, 'register_controls' ) );
$wp_customize->register_controls();
/** This filter is documented in wp-includes/class-wp-customize-manager.php */
do_action( 'customize_register', $wp_customize );
}
$wp_customize->_publish_changeset_values( $changeset_post->ID );
/*
* Trash the changeset post if revisions are not enabled. Unpublished
* changesets by default get garbage collected due to the auto-draft status.
* When a changeset post is published, however, it would no longer get cleaned
* out. This is a problem when the changeset posts are never displayed anywhere,
* since they would just be endlessly piling up. So here we use the revisions
* feature to indicate whether or not a published changeset should get trashed
* and thus garbage collected.
*/
if ( ! wp_revisions_enabled( $changeset_post ) ) {
$wp_customize->trash_changeset_post( $changeset_post->ID );
}
}
/**
* Filters changeset post data upon insert to ensure post_name is intact.
*
* This is needed to prevent the post_name from being dropped when the post is
* transitioned into pending status by a contributor.
*
* @since 4.7.0
*
* @see wp_insert_post()
*
* @param array $post_data An array of slashed post data.
* @param array $supplied_post_data An array of sanitized, but otherwise unmodified post data.
* @return array Filtered data.
*/
function _wp_customize_changeset_filter_insert_post_data( $post_data, $supplied_post_data ) {
if ( isset( $post_data['post_type'] ) && 'customize_changeset' === $post_data['post_type'] ) {
// Prevent post_name from being dropped, such as when contributor saves a changeset post as pending.
if ( empty( $post_data['post_name'] ) && ! empty( $supplied_post_data['post_name'] ) ) {
$post_data['post_name'] = $supplied_post_data['post_name'];
}
}
return $post_data;
}
/**
* Adds settings for the customize-loader script.
*
* @since 3.4.0
*/
function _wp_customize_loader_settings() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
$cross_domain = ( strtolower( $admin_origin['host'] ) !== strtolower( $home_origin['host'] ) );
$browser = array(
'mobile' => wp_is_mobile(),
'ios' => wp_is_mobile() && preg_match( '/iPad|iPod|iPhone/', $_SERVER['HTTP_USER_AGENT'] ),
);
$settings = array(
'url' => esc_url( admin_url( 'customize.php' ) ),
'isCrossDomain' => $cross_domain,
'browser' => $browser,
'l10n' => array(
'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
'mainIframeTitle' => __( 'Customizer' ),
),
);
$script = 'var _wpCustomizeLoaderSettings = ' . wp_json_encode( $settings ) . ';';
$wp_scripts = wp_scripts();
$data = $wp_scripts->get_data( 'customize-loader', 'data' );
if ( $data ) {
$script = "$data\n$script";
}
$wp_scripts->add_data( 'customize-loader', 'data', $script );
}
/**
* Returns a URL to load the Customizer.
*
* @since 3.4.0
*
* @param string $stylesheet Optional. Theme to customize. Defaults to active theme.
* The theme's stylesheet will be urlencoded if necessary.
* @return string
*/
function wp_customize_url( $stylesheet = '' ) {
$url = admin_url( 'customize.php' );
if ( $stylesheet ) {
$url .= '?theme=' . urlencode( $stylesheet );
}
return esc_url( $url );
}
/**
* Prints a script to check whether or not the Customizer is supported,
* and apply either the no-customize-support or customize-support class
* to the body.
*
* This function MUST be called inside the body tag.
*
* Ideally, call this function immediately after the body tag is opened.
* This prevents a flash of unstyled content.
*
* It is also recommended that you add the "no-customize-support" class
* to the body tag by default.
*
* @since 3.4.0
* @since 4.7.0 Support for IE8 and below is explicitly removed via conditional comments.
* @since 5.5.0 IE8 and older are no longer supported.
*/
function wp_customize_support_script() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
$cross_domain = ( strtolower( $admin_origin['host'] ) !== strtolower( $home_origin['host'] ) );
ob_start();
?>
<script>
(function() {
var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
<?php if ( $cross_domain ) : ?>
request = (function(){ var xhr = new XMLHttpRequest(); return ('withCredentials' in xhr); })();
<?php else : ?>
request = true;
<?php endif; ?>
b[c] = b[c].replace( rcs, ' ' );
// The customizer requires postMessage and CORS (if the site is cross domain).
b[c] += ( window.postMessage && request ? ' ' : ' no-' ) + cs;
}());
</script>
<?php
wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
}
/**
* Whether the site is being previewed in the Customizer.
*
* @since 4.0.0
*
* @global WP_Customize_Manager $wp_customize Customizer instance.
*
* @return bool True if the site is being previewed in the Customizer, false otherwise.
*/
function is_customize_preview() {
global $wp_customize;
return ( $wp_customize instanceof WP_Customize_Manager ) && $wp_customize->is_preview();
}
/**
* Makes sure that auto-draft posts get their post_date bumped or status changed
* to draft to prevent premature garbage-collection.
*
* When a changeset is updated but remains an auto-draft, ensure the post_date
* for the auto-draft posts remains the same so that it will be
* garbage-collected at the same time by `wp_delete_auto_drafts()`. Otherwise,
* if the changeset is updated to be a draft then update the posts
* to have a far-future post_date so that they will never be garbage collected
* unless the changeset post itself is deleted.
*
* When a changeset is updated to be a persistent draft or to be scheduled for
* publishing, then transition any dependent auto-drafts to a draft status so
* that they likewise will not be garbage-collected but also so that they can
* be edited in the admin before publishing since there is not yet a post/page
* editing flow in the Customizer. See #39752.
*
* @link https://core.trac.wordpress.org/ticket/39752
*
* @since 4.8.0
* @access private
* @see wp_delete_auto_drafts()
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $new_status Transition to this post status.
* @param string $old_status Previous post status.
* @param \WP_Post $post Post data.
*/
function _wp_keep_alive_customize_changeset_dependent_auto_drafts( $new_status, $old_status, $post ) {
global $wpdb;
unset( $old_status );
// Short-circuit if not a changeset or if the changeset was published.
if ( 'customize_changeset' !== $post->post_type || 'publish' === $new_status ) {
return;
}
$data = json_decode( $post->post_content, true );
if ( empty( $data['nav_menus_created_posts']['value'] ) ) {
return;
}
/*
* Actually, in lieu of keeping alive, trash any customization drafts here if the changeset itself is
* getting trashed. This is needed because when a changeset transitions to a draft, then any of the
* dependent auto-draft post/page stubs will also get transitioned to customization drafts which
* are then visible in the WP Admin. We cannot wait for the deletion of the changeset in which
* _wp_delete_customize_changeset_dependent_auto_drafts() will be called, since they need to be
* trashed to remove from visibility immediately.
*/
if ( 'trash' === $new_status ) {
foreach ( $data['nav_menus_created_posts']['value'] as $post_id ) {
if ( ! empty( $post_id ) && 'draft' === get_post_status( $post_id ) ) {
wp_trash_post( $post_id );
}
}
return;
}
$post_args = array();
if ( 'auto-draft' === $new_status ) {
/*
* Keep the post date for the post matching the changeset
* so that it will not be garbage-collected before the changeset.
*/
$post_args['post_date'] = $post->post_date; // Note wp_delete_auto_drafts() only looks at this date.
} else {
/*
* Since the changeset no longer has an auto-draft (and it is not published)
* it is now a persistent changeset, a long-lived draft, and so any
* associated auto-draft posts should likewise transition into having a draft
* status. These drafts will be treated differently than regular drafts in
* that they will be tied to the given changeset. The publish meta box is
* replaced with a notice about how the post is part of a set of customized changes
* which will be published when the changeset is published.
*/
$post_args['post_status'] = 'draft';
}
foreach ( $data['nav_menus_created_posts']['value'] as $post_id ) {
if ( empty( $post_id ) || 'auto-draft' !== get_post_status( $post_id ) ) {
continue;
}
$wpdb->update(
$wpdb->posts,
$post_args,
array( 'ID' => $post_id )
);
clean_post_cache( $post_id );
}
}
/**
* Creates the initial theme features when the 'setup_theme' action is fired.
*
* See {@see 'setup_theme'}.
*
* @since 5.5.0
* @since 6.0.1 The `block-templates` feature was added.
*/
function create_initial_theme_features() {
register_theme_feature(
'align-wide',
array(
'description' => __( 'Whether theme opts in to wide alignment CSS class.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'automatic-feed-links',
array(
'description' => __( 'Whether posts and comments RSS feed links are added to head.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'block-templates',
array(
'description' => __( 'Whether a theme uses block-based templates.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'block-template-parts',
array(
'description' => __( 'Whether a theme uses block-based template parts.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'custom-background',
array(
'description' => __( 'Custom background if defined by the theme.' ),
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'properties' => array(
'default-image' => array(
'type' => 'string',
'format' => 'uri',
),
'default-preset' => array(
'type' => 'string',
'enum' => array(
'default',
'fill',
'fit',
'repeat',
'custom',
),
),
'default-position-x' => array(
'type' => 'string',
'enum' => array(
'left',
'center',
'right',
),
),
'default-position-y' => array(
'type' => 'string',
'enum' => array(
'left',
'center',
'right',
),
),
'default-size' => array(
'type' => 'string',
'enum' => array(
'auto',
'contain',
'cover',
),
),
'default-repeat' => array(
'type' => 'string',
'enum' => array(
'repeat-x',
'repeat-y',
'repeat',
'no-repeat',
),
),
'default-attachment' => array(
'type' => 'string',
'enum' => array(
'scroll',
'fixed',
),
),
'default-color' => array(
'type' => 'string',
),
),
),
),
)
);
register_theme_feature(
'custom-header',
array(
'description' => __( 'Custom header if defined by the theme.' ),
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'properties' => array(
'default-image' => array(
'type' => 'string',
'format' => 'uri',
),
'random-default' => array(
'type' => 'boolean',
),
'width' => array(
'type' => 'integer',
),
'height' => array(
'type' => 'integer',
),
'flex-height' => array(
'type' => 'boolean',
),
'flex-width' => array(
'type' => 'boolean',
),
'default-text-color' => array(
'type' => 'string',
),
'header-text' => array(
'type' => 'boolean',
),
'uploads' => array(
'type' => 'boolean',
),
'video' => array(
'type' => 'boolean',
),
),
),
),
)
);
register_theme_feature(
'custom-logo',
array(
'type' => 'object',
'description' => __( 'Custom logo if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'properties' => array(
'width' => array(
'type' => 'integer',
),
'height' => array(
'type' => 'integer',
),
'flex-width' => array(
'type' => 'boolean',
),
'flex-height' => array(
'type' => 'boolean',
),
'header-text' => array(
'type' => 'array',
'items' => array(
'type' => 'string',
),
),
'unlink-homepage-logo' => array(
'type' => 'boolean',
),
),
),
),
)
);
register_theme_feature(
'customize-selective-refresh-widgets',
array(
'description' => __( 'Whether the theme enables Selective Refresh for Widgets being managed with the Customizer.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'dark-editor-style',
array(
'description' => __( 'Whether theme opts in to the dark editor style UI.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-custom-colors',
array(
'description' => __( 'Whether the theme disables custom colors.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-custom-font-sizes',
array(
'description' => __( 'Whether the theme disables custom font sizes.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-custom-gradients',
array(
'description' => __( 'Whether the theme disables custom gradients.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-layout-styles',
array(
'description' => __( 'Whether the theme disables generated layout styles.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'editor-color-palette',
array(
'type' => 'array',
'description' => __( 'Custom color palette if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'slug' => array(
'type' => 'string',
),
'color' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-font-sizes',
array(
'type' => 'array',
'description' => __( 'Custom font sizes if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'size' => array(
'type' => 'number',
),
'slug' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-gradient-presets',
array(
'type' => 'array',
'description' => __( 'Custom gradient presets if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'gradient' => array(
'type' => 'string',
),
'slug' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-spacing-sizes',
array(
'type' => 'array',
'description' => __( 'Custom spacing sizes if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'size' => array(
'type' => 'string',
),
'slug' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-styles',
array(
'description' => __( 'Whether theme opts in to the editor styles CSS wrapper.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'html5',
array(
'type' => 'array',
'description' => __( 'Allows use of HTML5 markup for search forms, comment forms, comment lists, gallery, and caption.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'string',
'enum' => array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'script',
'style',
),
),
),
),
)
);
register_theme_feature(
'post-formats',
array(
'type' => 'array',
'description' => __( 'Post formats supported.' ),
'show_in_rest' => array(
'name' => 'formats',
'schema' => array(
'items' => array(
'type' => 'string',
'enum' => get_post_format_slugs(),
),
'default' => array( 'standard' ),
),
'prepare_callback' => static function ( $formats ) {
$formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
$formats = array_merge( array( 'standard' ), $formats );
return $formats;
},
),
)
);
register_theme_feature(
'post-thumbnails',
array(
'type' => 'array',
'description' => __( 'The post types that support thumbnails or true if all post types are supported.' ),
'show_in_rest' => array(
'type' => array( 'boolean', 'array' ),
'schema' => array(
'items' => array(
'type' => 'string',
),
),
),
)
);
register_theme_feature(
'responsive-embeds',
array(
'description' => __( 'Whether the theme supports responsive embedded content.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'title-tag',
array(
'description' => __( 'Whether the theme can manage the document title tag.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'wp-block-styles',
array(
'description' => __( 'Whether theme opts in to default WordPress block styles for viewing.' ),
'show_in_rest' => true,
)
);
}
/**
* Returns whether the active theme is a block-based theme or not.
*
* @since 5.9.0
*
* @return bool Whether the active theme is a block-based theme or not.
*/
function wp_is_block_theme() {
if ( empty( $GLOBALS['wp_theme_directories'] ) ) {
_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before the theme directory is registered.' ), '6.8.0' );
return false;
}
return wp_get_theme()->is_block_theme();
}
/**
* Given an element name, returns a class name.
*
* Alias of WP_Theme_JSON::get_element_class_name.
*
* @since 6.1.0
*
* @param string $element The name of the element.
*
* @return string The name of the class.
*/
function wp_theme_get_element_class_name( $element ) {
return WP_Theme_JSON::get_element_class_name( $element );
}
/**
* Adds default theme supports for block themes when the 'after_setup_theme' action fires.
*
* See {@see 'after_setup_theme'}.
*
* @since 5.9.0
* @access private
*/
function _add_default_theme_supports() {
if ( ! wp_is_block_theme() ) {
return;
}
add_theme_support( 'post-thumbnails' );
add_theme_support( 'responsive-embeds' );
add_theme_support( 'editor-styles' );
/*
* Makes block themes support HTML5 by default for the comment block and search form
* (which use default template functions) and `[caption]` and `[gallery]` shortcodes.
* Other blocks contain their own HTML5 markup.
*/
add_theme_support( 'html5', array( 'comment-form', 'comment-list', 'search-form', 'gallery', 'caption', 'style', 'script' ) );
add_theme_support( 'automatic-feed-links' );
add_filter( 'should_load_separate_core_block_assets', '__return_true' );
add_filter( 'should_load_block_assets_on_demand', '__return_true' );
/*
* Remove the Customizer's Menus panel when block theme is active.
*/
add_filter(
'customize_panel_active',
static function ( $active, WP_Customize_Panel $panel ) {
if (
'nav_menus' === $panel->id &&
! current_theme_supports( 'menus' ) &&
! current_theme_supports( 'widgets' )
) {
$active = false;
}
return $active;
},
10,
2
);
}
<?php
/**
* Sets up the default filters and actions for most
* of the WordPress hooks.
*
* This file is loaded very early in the bootstrap which
* means many functions are not yet available and site
* information such as if this is multisite is unknown.
* Before using functions besides `add_filter` and
* `add_action`, verify things will work as expected.
*
* If you need to remove a default hook, this file will
* give you the priority to use for removing the hook.
*
* Not all of the default hooks are found in this file.
* For instance, administration-related hooks are located in
* wp-admin/includes/admin-filters.php.
*
* If a hook should only be called from a specific context
* (admin area, multisite environment…), please move it
* to a more appropriate file instead.
*
* @package WordPress
*/
// Don't load directly.
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
// Strip, trim, kses, special chars for string saves.
foreach ( array( 'pre_term_name', 'pre_comment_author_name', 'pre_link_name', 'pre_link_target', 'pre_link_rel', 'pre_user_display_name', 'pre_user_first_name', 'pre_user_last_name', 'pre_user_nickname' ) as $filter ) {
add_filter( $filter, 'sanitize_text_field' );
add_filter( $filter, 'wp_filter_kses' );
add_filter( $filter, '_wp_specialchars', 30 );
}
// Strip, kses, special chars for string display.
foreach ( array( 'term_name', 'comment_author_name', 'link_name', 'link_target', 'link_rel', 'user_display_name', 'user_first_name', 'user_last_name', 'user_nickname' ) as $filter ) {
if ( is_admin() ) {
// These are expensive. Run only on admin pages for defense in depth.
add_filter( $filter, 'sanitize_text_field' );
add_filter( $filter, 'wp_kses_data' );
}
add_filter( $filter, '_wp_specialchars', 30 );
}
// Kses only for textarea saves.
foreach ( array( 'pre_term_description', 'pre_link_description', 'pre_link_notes', 'pre_user_description' ) as $filter ) {
add_filter( $filter, 'wp_filter_kses' );
}
// Kses only for textarea admin displays.
if ( is_admin() ) {
foreach ( array( 'term_description', 'link_description', 'link_notes', 'user_description' ) as $filter ) {
add_filter( $filter, 'wp_kses_data' );
}
add_filter( 'comment_text', 'wp_kses_post' );
}
// Email saves.
foreach ( array( 'pre_comment_author_email', 'pre_user_email' ) as $filter ) {
add_filter( $filter, 'trim' );
add_filter( $filter, 'sanitize_email' );
add_filter( $filter, 'wp_filter_kses' );
}
// Email admin display.
foreach ( array( 'comment_author_email', 'user_email' ) as $filter ) {
add_filter( $filter, 'sanitize_email' );
if ( is_admin() ) {
add_filter( $filter, 'wp_kses_data' );
}
}
// Save URL.
foreach ( array(
'pre_comment_author_url',
'pre_user_url',
'pre_link_url',
'pre_link_image',
'pre_link_rss',
'pre_post_guid',
) as $filter ) {
add_filter( $filter, 'wp_strip_all_tags' );
add_filter( $filter, 'sanitize_url' );
add_filter( $filter, 'wp_filter_kses' );
}
// Display URL.
foreach ( array( 'user_url', 'link_url', 'link_image', 'link_rss', 'comment_url', 'post_guid' ) as $filter ) {
if ( is_admin() ) {
add_filter( $filter, 'wp_strip_all_tags' );
}
add_filter( $filter, 'esc_url' );
if ( is_admin() ) {
add_filter( $filter, 'wp_kses_data' );
}
}
// Slugs.
add_filter( 'pre_term_slug', 'sanitize_title' );
add_filter( 'wp_insert_post_data', '_wp_customize_changeset_filter_insert_post_data', 10, 2 );
// Keys.
foreach ( array( 'pre_post_type', 'pre_post_status', 'pre_post_comment_status', 'pre_post_ping_status' ) as $filter ) {
add_filter( $filter, 'sanitize_key' );
}
// Mime types.
add_filter( 'pre_post_mime_type', 'sanitize_mime_type' );
add_filter( 'post_mime_type', 'sanitize_mime_type' );
// Meta.
add_filter( 'register_meta_args', '_wp_register_meta_args_allowed_list', 10, 2 );
// Counts.
add_action( 'admin_init', 'wp_schedule_update_user_counts' );
add_action( 'wp_update_user_counts', 'wp_schedule_update_user_counts', 10, 0 );
foreach ( array( 'user_register', 'deleted_user' ) as $action ) {
add_action( $action, 'wp_maybe_update_user_counts', 10, 0 );
}
// Post meta.
add_action( 'added_post_meta', 'wp_cache_set_posts_last_changed' );
add_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' );
add_action( 'deleted_post_meta', 'wp_cache_set_posts_last_changed' );
// User meta.
add_action( 'added_user_meta', 'wp_cache_set_users_last_changed' );
add_action( 'updated_user_meta', 'wp_cache_set_users_last_changed' );
add_action( 'deleted_user_meta', 'wp_cache_set_users_last_changed' );
add_action( 'add_user_role', 'wp_cache_set_users_last_changed' );
add_action( 'set_user_role', 'wp_cache_set_users_last_changed' );
add_action( 'remove_user_role', 'wp_cache_set_users_last_changed' );
// Term meta.
add_action( 'added_term_meta', 'wp_cache_set_terms_last_changed' );
add_action( 'updated_term_meta', 'wp_cache_set_terms_last_changed' );
add_action( 'deleted_term_meta', 'wp_cache_set_terms_last_changed' );
add_filter( 'get_term_metadata', 'wp_check_term_meta_support_prefilter' );
add_filter( 'add_term_metadata', 'wp_check_term_meta_support_prefilter' );
add_filter( 'update_term_metadata', 'wp_check_term_meta_support_prefilter' );
add_filter( 'delete_term_metadata', 'wp_check_term_meta_support_prefilter' );
add_filter( 'get_term_metadata_by_mid', 'wp_check_term_meta_support_prefilter' );
add_filter( 'update_term_metadata_by_mid', 'wp_check_term_meta_support_prefilter' );
add_filter( 'delete_term_metadata_by_mid', 'wp_check_term_meta_support_prefilter' );
add_filter( 'update_term_metadata_cache', 'wp_check_term_meta_support_prefilter' );
// Comment meta.
add_action( 'added_comment_meta', 'wp_cache_set_comments_last_changed' );
add_action( 'updated_comment_meta', 'wp_cache_set_comments_last_changed' );
add_action( 'deleted_comment_meta', 'wp_cache_set_comments_last_changed' );
// Places to balance tags on input.
foreach ( array( 'content_save_pre', 'excerpt_save_pre', 'comment_save_pre', 'pre_comment_content' ) as $filter ) {
add_filter( $filter, 'convert_invalid_entities' );
add_filter( $filter, 'balanceTags', 50 );
}
// Format strings for display.
foreach ( array( 'comment_author', 'term_name', 'link_name', 'link_description', 'link_notes', 'bloginfo', 'wp_title', 'document_title', 'widget_title' ) as $filter ) {
add_filter( $filter, 'wptexturize' );
add_filter( $filter, 'convert_chars' );
add_filter( $filter, 'esc_html' );
}
// Format WordPress.
foreach ( array( 'the_content', 'the_title', 'wp_title', 'document_title' ) as $filter ) {
add_filter( $filter, 'capital_P_dangit', 11 );
}
add_filter( 'comment_text', 'capital_P_dangit', 31 );
// Format titles.
foreach ( array( 'single_post_title', 'single_cat_title', 'single_tag_title', 'single_month_title', 'nav_menu_attr_title', 'nav_menu_description' ) as $filter ) {
add_filter( $filter, 'wptexturize' );
add_filter( $filter, 'strip_tags' );
}
// Format text area for display.
foreach ( array( 'term_description', 'get_the_post_type_description' ) as $filter ) {
add_filter( $filter, 'wptexturize' );
add_filter( $filter, 'convert_chars' );
add_filter( $filter, 'wpautop' );
add_filter( $filter, 'shortcode_unautop' );
}
// Format for RSS.
add_filter( 'term_name_rss', 'convert_chars' );
// Pre save hierarchy.
add_filter( 'wp_insert_post_parent', 'wp_check_post_hierarchy_for_loops', 10, 2 );
add_filter( 'wp_update_term_parent', 'wp_check_term_hierarchy_for_loops', 10, 3 );
// Display filters.
add_filter( 'the_title', 'wptexturize' );
add_filter( 'the_title', 'convert_chars' );
add_filter( 'the_title', 'trim' );
add_filter( 'the_content', 'apply_block_hooks_to_content_from_post_object', 8 ); // BEFORE do_blocks().
add_filter( 'the_content', 'do_blocks', 9 );
add_filter( 'the_content', 'wptexturize' );
add_filter( 'the_content', 'convert_smilies', 20 );
add_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'shortcode_unautop' );
add_filter( 'the_content', 'prepend_attachment' );
add_filter( 'the_content', 'wp_replace_insecure_home_url' );
add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop().
add_filter( 'the_content', 'wp_filter_content_tags', 12 ); // Runs after do_shortcode().
add_filter( 'the_excerpt', 'wptexturize' );
add_filter( 'the_excerpt', 'convert_smilies' );
add_filter( 'the_excerpt', 'convert_chars' );
add_filter( 'the_excerpt', 'wpautop' );
add_filter( 'the_excerpt', 'shortcode_unautop' );
add_filter( 'the_excerpt', 'wp_replace_insecure_home_url' );
add_filter( 'the_excerpt', 'wp_filter_content_tags', 12 );
add_filter( 'get_the_excerpt', 'wp_trim_excerpt', 10, 2 );
add_filter( 'the_post_thumbnail_caption', 'wptexturize' );
add_filter( 'the_post_thumbnail_caption', 'convert_smilies' );
add_filter( 'the_post_thumbnail_caption', 'convert_chars' );
add_filter( 'comment_text', 'wptexturize' );
add_filter( 'comment_text', 'convert_chars' );
add_filter( 'comment_text', 'make_clickable', 9 );
add_filter( 'comment_text', 'force_balance_tags', 25 );
add_filter( 'comment_text', 'convert_smilies', 20 );
add_filter( 'comment_text', 'wpautop', 30 );
add_filter( 'comment_excerpt', 'convert_chars' );
add_filter( 'list_cats', 'wptexturize' );
add_filter( 'wp_sprintf', 'wp_sprintf_l', 10, 2 );
add_filter( 'widget_text', 'balanceTags' );
add_filter( 'widget_text_content', 'capital_P_dangit', 11 );
add_filter( 'widget_text_content', 'wptexturize' );
add_filter( 'widget_text_content', 'convert_smilies', 20 );
add_filter( 'widget_text_content', 'wpautop' );
add_filter( 'widget_text_content', 'shortcode_unautop' );
add_filter( 'widget_text_content', 'wp_replace_insecure_home_url' );
add_filter( 'widget_text_content', 'do_shortcode', 11 ); // Runs after wpautop(); note that $post global will be null when shortcodes run.
add_filter( 'widget_text_content', 'wp_filter_content_tags', 12 ); // Runs after do_shortcode().
add_filter( 'widget_block_content', 'do_blocks', 9 );
add_filter( 'widget_block_content', 'do_shortcode', 11 );
add_filter( 'widget_block_content', 'wp_filter_content_tags', 12 ); // Runs after do_shortcode().
add_filter( 'block_type_metadata', 'wp_migrate_old_typography_shape' );
add_filter( 'wp_get_custom_css', 'wp_replace_insecure_home_url' );
// RSS filters.
add_filter( 'the_title_rss', 'strip_tags' );
add_filter( 'the_title_rss', 'ent2ncr', 8 );
add_filter( 'the_title_rss', 'esc_html' );
add_filter( 'the_content_rss', 'ent2ncr', 8 );
add_filter( 'the_content_feed', 'wp_staticize_emoji' );
add_filter( 'the_content_feed', '_oembed_filter_feed_content' );
add_filter( 'the_excerpt_rss', 'convert_chars' );
add_filter( 'the_excerpt_rss', 'ent2ncr', 8 );
add_filter( 'comment_author_rss', 'ent2ncr', 8 );
add_filter( 'comment_text_rss', 'ent2ncr', 8 );
add_filter( 'comment_text_rss', 'esc_html' );
add_filter( 'comment_text_rss', 'wp_staticize_emoji' );
add_filter( 'bloginfo_rss', 'ent2ncr', 8 );
add_filter( 'the_author', 'ent2ncr', 8 );
add_filter( 'the_guid', 'esc_url' );
// Email filters.
add_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
// Robots filters.
add_filter( 'wp_robots', 'wp_robots_noindex' );
add_filter( 'wp_robots', 'wp_robots_noindex_embeds' );
add_filter( 'wp_robots', 'wp_robots_noindex_search' );
add_filter( 'wp_robots', 'wp_robots_max_image_preview_large' );
// Mark site as no longer fresh.
foreach (
array(
'publish_post',
'publish_page',
'wp_ajax_save-widget',
'wp_ajax_widgets-order',
'customize_save_after',
'rest_after_save_widget',
'rest_delete_widget',
'rest_save_sidebar',
) as $action
) {
add_action( $action, '_delete_option_fresh_site', 0 );
}
// Misc filters.
add_filter( 'wp_default_autoload_value', 'wp_filter_default_autoload_value_via_option_size', 5, 4 ); // Allow the value to be overridden at the default priority.
add_filter( 'option_ping_sites', 'privacy_ping_filter' );
add_filter( 'option_blog_charset', '_wp_specialchars' ); // IMPORTANT: This must not be wp_specialchars() or esc_html() or it'll cause an infinite loop.
add_filter( 'option_blog_charset', '_canonical_charset' );
add_filter( 'option_home', '_config_wp_home' );
add_filter( 'option_siteurl', '_config_wp_siteurl' );
add_filter( 'tiny_mce_before_init', '_mce_set_direction' );
add_filter( 'teeny_mce_before_init', '_mce_set_direction' );
add_filter( 'pre_kses', 'wp_pre_kses_less_than' );
add_filter( 'pre_kses', 'wp_pre_kses_block_attributes', 10, 3 );
add_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 );
add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 );
add_filter( 'pre_comment_content', 'wp_rel_ugc', 15 );
add_filter( 'comment_email', 'antispambot' );
add_filter( 'option_tag_base', '_wp_filter_taxonomy_base' );
add_filter( 'option_category_base', '_wp_filter_taxonomy_base' );
add_filter( 'the_posts', '_close_comments_for_old_posts', 10, 2 );
add_filter( 'comments_open', '_close_comments_for_old_post', 10, 2 );
add_filter( 'pings_open', '_close_comments_for_old_post', 10, 2 );
add_filter( 'editable_slug', 'urldecode' );
add_filter( 'editable_slug', 'esc_textarea' );
add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' );
add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' );
add_filter( 'title_save_pre', 'trim' );
add_action( 'transition_comment_status', '_clear_modified_cache_on_transition_comment_status', 10, 2 );
add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 );
// REST API filters.
add_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' );
add_action( 'wp_head', 'rest_output_link_wp_head', 10, 0 );
add_action( 'template_redirect', 'rest_output_link_header', 11, 0 );
add_action( 'auth_cookie_malformed', 'rest_cookie_collect_status' );
add_action( 'auth_cookie_expired', 'rest_cookie_collect_status' );
add_action( 'auth_cookie_bad_username', 'rest_cookie_collect_status' );
add_action( 'auth_cookie_bad_hash', 'rest_cookie_collect_status' );
add_action( 'auth_cookie_valid', 'rest_cookie_collect_status' );
add_action( 'application_password_failed_authentication', 'rest_application_password_collect_status' );
add_action( 'application_password_did_authenticate', 'rest_application_password_collect_status', 10, 2 );
add_filter( 'rest_authentication_errors', 'rest_application_password_check_errors', 90 );
add_filter( 'rest_authentication_errors', 'rest_cookie_check_errors', 100 );
// Actions.
add_action( 'wp_head', '_wp_render_title_tag', 1 );
add_action( 'wp_head', 'wp_enqueue_scripts', 1 );
add_action( 'wp_head', 'wp_resource_hints', 2 );
add_action( 'wp_head', 'wp_preload_resources', 1 );
add_action( 'wp_head', 'feed_links', 2 );
add_action( 'wp_head', 'feed_links_extra', 3 );
add_action( 'wp_head', 'rsd_link' );
add_action( 'wp_head', 'locale_stylesheet' );
add_action( 'publish_future_post', 'check_and_publish_future_post', 10, 1 );
add_action( 'wp_head', 'wp_robots', 1 );
add_action( 'wp_head', 'print_emoji_detection_script', 7 );
add_action( 'wp_head', 'wp_print_styles', 8 );
add_action( 'wp_head', 'wp_print_head_scripts', 9 );
add_action( 'wp_head', 'wp_generator' );
add_action( 'wp_head', 'rel_canonical' );
add_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 );
add_action( 'wp_head', 'wp_custom_css_cb', 101 );
add_action( 'wp_head', 'wp_site_icon', 99 );
add_action( 'wp_footer', 'wp_print_speculation_rules' );
add_action( 'wp_footer', 'wp_print_footer_scripts', 20 );
add_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );
add_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
add_action( 'init', '_register_core_block_patterns_and_categories' );
add_action( 'init', 'check_theme_switched', 99 );
add_action( 'init', array( 'WP_Block_Supports', 'init' ), 22 );
add_action( 'switch_theme', 'wp_clean_theme_json_cache' );
add_action( 'start_previewing_theme', 'wp_clean_theme_json_cache' );
add_action( 'after_switch_theme', '_wp_menus_changed' );
add_action( 'after_switch_theme', '_wp_sidebars_changed' );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_emoji_styles' );
add_action( 'wp_print_styles', 'print_emoji_styles' ); // Retained for backwards-compatibility. Unhooked by wp_enqueue_emoji_styles().
if (
// Comment reply link.
isset( $_GET['replytocom'] )
||
// Unapproved comment preview.
( isset( $_GET['unapproved'] ) && isset( $_GET['moderation-hash'] ) )
) {
add_filter( 'wp_robots', 'wp_robots_no_robots' );
}
// Login actions.
add_action( 'login_head', 'wp_robots', 1 );
add_filter( 'login_head', 'wp_resource_hints', 8 );
add_action( 'login_head', 'wp_print_head_scripts', 9 );
add_action( 'login_head', 'print_admin_styles', 9 );
add_action( 'login_head', 'wp_site_icon', 99 );
add_action( 'login_footer', 'wp_print_footer_scripts', 20 );
add_action( 'login_init', 'send_frame_options_header', 10, 0 );
add_action( 'login_init', 'wp_admin_headers' );
// Feed generator tags.
foreach ( array( 'rss2_head', 'commentsrss2_head', 'rss_head', 'rdf_header', 'atom_head', 'comments_atom_head', 'opml_head', 'app_head' ) as $action ) {
add_action( $action, 'the_generator' );
}
// Feed Site Icon.
add_action( 'atom_head', 'atom_site_icon' );
add_action( 'rss2_head', 'rss2_site_icon' );
// WP Cron.
if ( ! defined( 'DOING_CRON' ) ) {
add_action( 'init', 'wp_cron' );
}
// HTTPS migration.
add_action( 'update_option_home', 'wp_update_https_migration_required', 10, 2 );
// 2 Actions 2 Furious.
add_action( 'do_feed_rdf', 'do_feed_rdf', 10, 0 );
add_action( 'do_feed_rss', 'do_feed_rss', 10, 0 );
add_action( 'do_feed_rss2', 'do_feed_rss2', 10, 1 );
add_action( 'do_feed_atom', 'do_feed_atom', 10, 1 );
add_action( 'do_pings', 'do_all_pings', 10, 0 );
add_action( 'do_all_pings', 'do_all_pingbacks', 10, 0 );
add_action( 'do_all_pings', 'do_all_enclosures', 10, 0 );
add_action( 'do_all_pings', 'do_all_trackbacks', 10, 0 );
add_action( 'do_all_pings', 'generic_ping', 10, 0 );
add_action( 'do_robots', 'do_robots' );
add_action( 'do_favicon', 'do_favicon' );
add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 3 );
add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' );
add_action( 'init', 'smilies_init', 5 );
add_action( 'plugins_loaded', 'wp_maybe_load_widgets', 0 );
add_action( 'plugins_loaded', 'wp_maybe_load_embeds', 0 );
add_action( 'shutdown', 'wp_ob_end_flush_all', 1 );
// Create a revision whenever a post is updated.
add_action( 'wp_after_insert_post', 'wp_save_post_revision_on_insert', 9, 3 );
add_action( 'post_updated', 'wp_save_post_revision', 10, 1 );
add_action( 'publish_post', '_publish_post_hook', 5, 1 );
add_action( 'transition_post_status', '_transition_post_status', 5, 3 );
add_action( 'transition_post_status', '_update_term_count_on_transition_post_status', 10, 3 );
add_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce' );
// Privacy.
add_action( 'user_request_action_confirmed', '_wp_privacy_account_request_confirmed' );
add_action( 'user_request_action_confirmed', '_wp_privacy_send_request_confirmation_notification', 12 ); // After request marked as completed.
add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter' );
add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_media_personal_data_exporter' );
add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_user_personal_data_exporter', 1 );
add_filter( 'wp_privacy_personal_data_erasers', 'wp_register_comment_personal_data_eraser' );
add_action( 'init', 'wp_schedule_delete_old_privacy_export_files' );
add_action( 'wp_privacy_delete_old_export_files', 'wp_privacy_delete_old_export_files' );
// Cron tasks.
add_action( 'wp_scheduled_delete', 'wp_scheduled_delete' );
add_action( 'wp_scheduled_auto_draft_delete', 'wp_delete_auto_drafts' );
add_action( 'importer_scheduled_cleanup', 'wp_delete_attachment' );
add_action( 'upgrader_scheduled_cleanup', 'wp_delete_attachment' );
add_action( 'delete_expired_transients', 'delete_expired_transients' );
// Navigation menu actions.
add_action( 'delete_post', '_wp_delete_post_menu_item' );
add_action( 'delete_term', '_wp_delete_tax_menu_item', 10, 3 );
add_action( 'transition_post_status', '_wp_auto_add_pages_to_menu', 10, 3 );
add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' );
// Post Thumbnail specific image filtering.
add_action( 'begin_fetch_post_thumbnail_html', '_wp_post_thumbnail_class_filter_add' );
add_action( 'end_fetch_post_thumbnail_html', '_wp_post_thumbnail_class_filter_remove' );
add_action( 'begin_fetch_post_thumbnail_html', '_wp_post_thumbnail_context_filter_add' );
add_action( 'end_fetch_post_thumbnail_html', '_wp_post_thumbnail_context_filter_remove' );
// Redirect old slugs.
add_action( 'template_redirect', 'wp_old_slug_redirect' );
add_action( 'post_updated', 'wp_check_for_changed_slugs', 12, 3 );
add_action( 'attachment_updated', 'wp_check_for_changed_slugs', 12, 3 );
// Redirect old dates.
add_action( 'post_updated', 'wp_check_for_changed_dates', 12, 3 );
add_action( 'attachment_updated', 'wp_check_for_changed_dates', 12, 3 );
// Nonce check for post previews.
add_action( 'init', '_show_post_preview' );
// Output JS to reset window.name for previews.
add_action( 'wp_head', 'wp_post_preview_js', 1 );
// Timezone.
add_filter( 'pre_option_gmt_offset', 'wp_timezone_override_offset' );
// If the upgrade hasn't run yet, assume link manager is used.
add_filter( 'default_option_link_manager_enabled', '__return_true' );
// This option no longer exists; tell plugins we always support auto-embedding.
add_filter( 'pre_option_embed_autourls', '__return_true' );
// Default settings for heartbeat.
add_filter( 'heartbeat_settings', 'wp_heartbeat_settings' );
// Check if the user is logged out.
add_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
add_filter( 'heartbeat_send', 'wp_auth_check' );
add_filter( 'heartbeat_nopriv_send', 'wp_auth_check' );
// Default authentication filters.
add_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_application_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_spam_check', 99 );
add_filter( 'determine_current_user', 'wp_validate_auth_cookie' );
add_filter( 'determine_current_user', 'wp_validate_logged_in_cookie', 20 );
add_filter( 'determine_current_user', 'wp_validate_application_password', 20 );
// Split term updates.
add_action( 'admin_init', '_wp_check_for_scheduled_split_terms' );
add_action( 'split_shared_term', '_wp_check_split_default_terms', 10, 4 );
add_action( 'split_shared_term', '_wp_check_split_terms_in_menus', 10, 4 );
add_action( 'split_shared_term', '_wp_check_split_nav_menu_terms', 10, 4 );
add_action( 'wp_split_shared_term_batch', '_wp_batch_split_terms' );
// Comment type updates.
add_action( 'admin_init', '_wp_check_for_scheduled_update_comment_type' );
add_action( 'wp_update_comment_type_batch', '_wp_batch_update_comment_type' );
// Email notifications.
add_action( 'comment_post', 'wp_new_comment_notify_moderator' );
add_action( 'comment_post', 'wp_new_comment_notify_postauthor' );
add_action( 'after_password_reset', 'wp_password_change_notification' );
add_action( 'register_new_user', 'wp_send_new_user_notifications' );
add_action( 'edit_user_created_user', 'wp_send_new_user_notifications', 10, 2 );
// REST API actions.
add_action( 'init', 'rest_api_init' );
add_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
add_action( 'rest_api_init', 'register_initial_settings', 10 );
add_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
add_action( 'parse_request', 'rest_api_loaded' );
// Sitemaps actions.
add_action( 'init', 'wp_sitemaps_get_server' );
/**
* Filters formerly mixed into wp-includes.
*/
// Theme.
add_action( 'setup_theme', 'create_initial_theme_features', 0 );
add_action( 'after_setup_theme', '_add_default_theme_supports', 1 );
add_action( 'wp_loaded', '_custom_header_background_just_in_time' );
add_action( 'wp_head', '_custom_logo_header_styles' );
add_action( 'plugins_loaded', '_wp_customize_include' );
add_action( 'transition_post_status', '_wp_customize_publish_changeset', 10, 3 );
add_action( 'admin_enqueue_scripts', '_wp_customize_loader_settings' );
add_action( 'delete_attachment', '_delete_attachment_theme_mod' );
add_action( 'transition_post_status', '_wp_keep_alive_customize_changeset_dependent_auto_drafts', 20, 3 );
// Block Theme Previews.
add_action( 'plugins_loaded', 'wp_initialize_theme_preview_hooks', 1 );
// Site preview for Classic Theme.
add_action( 'init', 'wp_initialize_site_preview_hooks', 1 );
// Calendar widget cache.
add_action( 'save_post', 'delete_get_calendar_cache' );
add_action( 'delete_post', 'delete_get_calendar_cache' );
add_action( 'update_option_start_of_week', 'delete_get_calendar_cache' );
add_action( 'update_option_gmt_offset', 'delete_get_calendar_cache' );
// Author.
add_action( 'transition_post_status', '__clear_multi_author_cache' );
// Post.
add_action( 'init', 'create_initial_post_types', 0 ); // Highest priority.
add_action( 'admin_menu', '_add_post_type_submenus' );
add_action( 'before_delete_post', '_reset_front_page_settings_for_post' );
add_action( 'wp_trash_post', '_reset_front_page_settings_for_post' );
add_action( 'change_locale', 'create_initial_post_types' );
// Post Formats.
add_filter( 'request', '_post_format_request' );
add_filter( 'term_link', '_post_format_link', 10, 3 );
add_filter( 'get_post_format', '_post_format_get_term' );
add_filter( 'get_terms', '_post_format_get_terms', 10, 3 );
add_filter( 'wp_get_object_terms', '_post_format_wp_get_object_terms' );
// KSES.
add_action( 'init', 'kses_init' );
add_action( 'set_current_user', 'kses_init' );
// Script Loader.
add_action( 'wp_default_scripts', 'wp_default_scripts' );
add_action( 'wp_default_scripts', 'wp_default_packages' );
add_action( 'wp_default_scripts', 'wp_default_script_modules' );
add_action( 'wp_enqueue_scripts', 'wp_localize_jquery_ui_datepicker', 1000 );
add_action( 'wp_enqueue_scripts', 'wp_common_block_scripts_and_styles' );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_classic_theme_styles' );
add_action( 'admin_enqueue_scripts', 'wp_localize_jquery_ui_datepicker', 1000 );
add_action( 'admin_enqueue_scripts', 'wp_common_block_scripts_and_styles' );
add_action( 'enqueue_block_assets', 'wp_enqueue_classic_theme_styles' );
add_action( 'enqueue_block_assets', 'wp_enqueue_registered_block_scripts_and_styles' );
add_action( 'enqueue_block_assets', 'enqueue_block_styles_assets', 30 );
/*
* `wp_enqueue_registered_block_scripts_and_styles` is bound to both
* `enqueue_block_editor_assets` and `enqueue_block_assets` hooks
* since the introduction of the block editor in WordPress 5.0.
*
* The way this works is that the block assets are loaded before any other assets.
* For example, this is the order of styles for the editor:
*
* - front styles registered for blocks, via `styles` handle (block.json)
* - editor styles registered for blocks, via `editorStyles` handle (block.json)
* - editor styles enqueued via `enqueue_block_editor_assets` hook
* - front styles enqueued via `enqueue_block_assets` hook
*/
add_action( 'enqueue_block_editor_assets', 'wp_enqueue_registered_block_scripts_and_styles' );
add_action( 'enqueue_block_editor_assets', 'enqueue_editor_block_styles_assets' );
add_action( 'enqueue_block_editor_assets', 'wp_enqueue_editor_block_directory_assets' );
add_action( 'enqueue_block_editor_assets', 'wp_enqueue_editor_format_library_assets' );
add_action( 'enqueue_block_editor_assets', 'wp_enqueue_global_styles_css_custom_properties' );
add_action( 'wp_print_scripts', 'wp_just_in_time_script_localization' );
add_filter( 'print_scripts_array', 'wp_prototype_before_jquery' );
add_action( 'customize_controls_print_styles', 'wp_resource_hints', 1 );
add_action( 'admin_head', 'wp_check_widget_editor_deps' );
// Global styles can be enqueued in both the header and the footer. See https://core.trac.wordpress.org/ticket/53494.
add_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' );
add_action( 'wp_footer', 'wp_enqueue_global_styles', 1 );
// Block supports, and other styles parsed and stored in the Style Engine.
add_action( 'wp_enqueue_scripts', 'wp_enqueue_stored_styles' );
add_action( 'wp_footer', 'wp_enqueue_stored_styles', 1 );
add_action( 'wp_default_styles', 'wp_default_styles' );
add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
add_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 );
add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in <head>.
add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer.
/*
* Block specific actions and filters.
*/
// Footnotes Block.
add_action( 'init', '_wp_footnotes_kses_init' );
add_action( 'set_current_user', '_wp_footnotes_kses_init' );
add_filter( 'force_filtered_html_on_import', '_wp_footnotes_force_filtered_html_on_import_filter', 999 );
/*
* Disable "Post Attributes" for wp_navigation post type. The attributes are
* also conditionally enabled when a site has custom templates. Block Theme
* templates can be available for every post type.
*/
add_filter( 'theme_wp_navigation_templates', '__return_empty_array' );
// Taxonomy.
add_action( 'init', 'create_initial_taxonomies', 0 ); // Highest priority.
add_action( 'change_locale', 'create_initial_taxonomies' );
// Canonical.
add_action( 'template_redirect', 'redirect_canonical' );
add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
// Media.
add_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );
add_action( 'customize_controls_enqueue_scripts', 'wp_plupload_default_settings' );
add_action( 'plugins_loaded', '_wp_add_additional_image_sizes', 0 );
add_filter( 'plupload_default_settings', 'wp_show_heic_upload_error' );
// Nav menu.
add_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once', 10, 2 );
add_filter( 'nav_menu_css_class', 'wp_nav_menu_remove_menu_item_has_children_class', 10, 4 );
// Widgets.
add_action( 'after_setup_theme', 'wp_setup_widgets_block_editor', 1 );
add_action( 'init', 'wp_widgets_init', 1 );
add_action( 'change_locale', array( 'WP_Widget_Media', 'reset_default_labels' ) );
add_action( 'widgets_init', '_wp_block_theme_register_classic_sidebars', 1 );
// Admin Bar.
// Don't remove. Wrong way to disable.
add_action( 'template_redirect', '_wp_admin_bar_init', 0 );
add_action( 'admin_init', '_wp_admin_bar_init' );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_admin_bar_bump_styles' );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_admin_bar_header_styles' );
add_action( 'admin_enqueue_scripts', 'wp_enqueue_admin_bar_header_styles' );
add_action( 'before_signup_header', '_wp_admin_bar_init' );
add_action( 'activate_header', '_wp_admin_bar_init' );
add_action( 'wp_body_open', 'wp_admin_bar_render', 0 );
add_action( 'wp_footer', 'wp_admin_bar_render', 1000 ); // Back-compat for themes not using `wp_body_open`.
add_action( 'in_admin_header', 'wp_admin_bar_render', 0 );
// Former admin filters that can also be hooked on the front end.
add_action( 'media_buttons', 'media_buttons' );
add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
add_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 );
// Embeds.
add_action( 'rest_api_init', 'wp_oembed_register_route' );
add_filter( 'rest_pre_serve_request', '_oembed_rest_pre_serve_request', 10, 4 );
add_action( 'wp_head', 'wp_oembed_add_discovery_links' );
add_action( 'wp_head', 'wp_oembed_add_host_js' ); // Back-compat for sites disabling oEmbed host JS by removing action.
add_filter( 'embed_oembed_html', 'wp_maybe_enqueue_oembed_host_js' );
add_action( 'embed_head', 'enqueue_embed_scripts', 1 );
add_action( 'embed_head', 'print_emoji_detection_script' );
add_action( 'embed_head', 'wp_enqueue_embed_styles', 9 );
add_action( 'embed_head', 'print_embed_styles' ); // Retained for backwards-compatibility. Unhooked by wp_enqueue_embed_styles().
add_action( 'embed_head', 'wp_print_head_scripts', 20 );
add_action( 'embed_head', 'wp_print_styles', 20 );
add_action( 'embed_head', 'wp_robots' );
add_action( 'embed_head', 'rel_canonical' );
add_action( 'embed_head', 'locale_stylesheet', 30 );
add_action( 'enqueue_embed_scripts', 'wp_enqueue_emoji_styles' );
add_action( 'embed_content_meta', 'print_embed_comments_button' );
add_action( 'embed_content_meta', 'print_embed_sharing_button' );
add_action( 'embed_footer', 'print_embed_sharing_dialog' );
add_action( 'embed_footer', 'print_embed_scripts' );
add_action( 'embed_footer', 'wp_print_footer_scripts', 20 );
add_filter( 'excerpt_more', 'wp_embed_excerpt_more', 20 );
add_filter( 'the_excerpt_embed', 'wptexturize' );
add_filter( 'the_excerpt_embed', 'convert_chars' );
add_filter( 'the_excerpt_embed', 'wpautop' );
add_filter( 'the_excerpt_embed', 'shortcode_unautop' );
add_filter( 'the_excerpt_embed', 'wp_embed_excerpt_attachment' );
add_filter( 'oembed_dataparse', 'wp_filter_oembed_iframe_title_attribute', 5, 3 );
add_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10, 3 );
add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 );
add_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10, 3 );
// Capabilities.
add_filter( 'user_has_cap', 'wp_maybe_grant_install_languages_cap', 1 );
add_filter( 'user_has_cap', 'wp_maybe_grant_resume_extensions_caps', 1 );
add_filter( 'user_has_cap', 'wp_maybe_grant_site_health_caps', 1, 4 );
// Block templates post type and rendering.
add_filter( 'render_block_context', '_block_template_render_without_post_block_context' );
add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 );
add_action( 'save_post_wp_template_part', 'wp_set_unique_slug_on_create_template_part' );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_template_skip_link' );
add_action( 'wp_footer', 'the_block_template_skip_link' ); // Retained for backwards-compatibility. Unhooked by wp_enqueue_block_template_skip_link().
add_action( 'after_setup_theme', 'wp_enable_block_templates', 1 );
add_action( 'wp_loaded', '_add_template_loader_filters' );
// wp_navigation post type.
add_filter( 'rest_wp_navigation_item_schema', array( 'WP_Navigation_Fallback', 'update_wp_navigation_post_schema' ) );
// Fluid typography.
add_filter( 'render_block', 'wp_render_typography_support', 10, 2 );
// User preferences.
add_action( 'init', 'wp_register_persisted_preferences_meta' );
// CPT wp_block custom postmeta field.
add_action( 'init', 'wp_create_initial_post_meta' );
// Include revisioned meta when considering whether a post revision has changed.
add_filter( 'wp_save_post_revision_post_has_changed', 'wp_check_revisioned_meta_fields_have_changed', 10, 3 );
// Save revisioned post meta immediately after a revision is saved
add_action( '_wp_put_post_revision', 'wp_save_revisioned_meta_fields', 10, 2 );
// Include revisioned meta when creating or updating an autosave revision.
add_action( 'wp_creating_autosave', 'wp_autosave_post_revisioned_meta_fields' );
// When restoring revisions, also restore revisioned meta.
add_action( 'wp_restore_post_revision', 'wp_restore_post_revision_meta', 10, 2 );
// Font management.
add_action( 'wp_head', 'wp_print_font_faces', 50 );
add_action( 'deleted_post', '_wp_after_delete_font_family', 10, 2 );
add_action( 'before_delete_post', '_wp_before_delete_font_face', 10, 2 );
add_action( 'init', '_wp_register_default_font_collections' );
// Add ignoredHookedBlocks metadata attribute to the template and template part post types.
add_filter( 'rest_pre_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes' );
add_filter( 'rest_pre_insert_wp_template_part', 'inject_ignored_hooked_blocks_metadata_attributes' );
// Update ignoredHookedBlocks postmeta for some post types.
add_filter( 'rest_pre_insert_page', 'update_ignored_hooked_blocks_postmeta' );
add_filter( 'rest_pre_insert_post', 'update_ignored_hooked_blocks_postmeta' );
add_filter( 'rest_pre_insert_wp_block', 'update_ignored_hooked_blocks_postmeta' );
add_filter( 'rest_pre_insert_wp_navigation', 'update_ignored_hooked_blocks_postmeta' );
// Inject hooked blocks into the Posts endpoint REST response for some given post types.
add_filter( 'rest_prepare_page', 'insert_hooked_blocks_into_rest_response', 10, 2 );
add_filter( 'rest_prepare_post', 'insert_hooked_blocks_into_rest_response', 10, 2 );
add_filter( 'rest_prepare_wp_block', 'insert_hooked_blocks_into_rest_response', 10, 2 );
add_filter( 'rest_prepare_wp_navigation', 'insert_hooked_blocks_into_rest_response', 10, 2 );
unset( $filter, $action );
<?php
/**
* WordPress List utility class
*
* @package WordPress
* @since 4.7.0
*/
/**
* List utility.
*
* Utility class to handle operations on an array of objects or arrays.
*
* @since 4.7.0
*/
#[AllowDynamicProperties]
class WP_List_Util {
/**
* The input array.
*
* @since 4.7.0
* @var array
*/
private $input = array();
/**
* The output array.
*
* @since 4.7.0
* @var array
*/
private $output = array();
/**
* Temporary arguments for sorting.
*
* @since 4.7.0
* @var string[]
*/
private $orderby = array();
/**
* Constructor.
*
* Sets the input array.
*
* @since 4.7.0
*
* @param array $input Array to perform operations on.
*/
public function __construct( $input ) {
$this->output = $input;
$this->input = $input;
}
/**
* Returns the original input array.
*
* @since 4.7.0
*
* @return array The input array.
*/
public function get_input() {
return $this->input;
}
/**
* Returns the output array.
*
* @since 4.7.0
*
* @return array The output array.
*/
public function get_output() {
return $this->output;
}
/**
* Filters the list, based on a set of key => value arguments.
*
* Retrieves the objects from the list that match the given arguments.
* Key represents property name, and value represents property value.
*
* If an object has more properties than those specified in arguments,
* that will not disqualify it. When using the 'AND' operator,
* any missing properties will disqualify it.
*
* @since 4.7.0
*
* @param array $args Optional. An array of key => value arguments to match
* against each object. Default empty array.
* @param string $operator Optional. The logical operation to perform. 'AND' means
* all elements from the array must match. 'OR' means only
* one element needs to match. 'NOT' means no elements may
* match. Default 'AND'.
* @return array Array of found values.
*/
public function filter( $args = array(), $operator = 'AND' ) {
if ( empty( $args ) ) {
return $this->output;
}
$operator = strtoupper( $operator );
if ( ! in_array( $operator, array( 'AND', 'OR', 'NOT' ), true ) ) {
$this->output = array();
return $this->output;
}
$count = count( $args );
$filtered = array();
foreach ( $this->output as $key => $obj ) {
$matched = 0;
foreach ( $args as $m_key => $m_value ) {
if ( is_array( $obj ) ) {
// Treat object as an array.
if ( array_key_exists( $m_key, $obj ) && ( $m_value == $obj[ $m_key ] ) ) {
++$matched;
}
} elseif ( is_object( $obj ) ) {
// Treat object as an object.
if ( isset( $obj->{$m_key} ) && ( $m_value == $obj->{$m_key} ) ) {
++$matched;
}
}
}
if ( ( 'AND' === $operator && $matched === $count )
|| ( 'OR' === $operator && $matched > 0 )
|| ( 'NOT' === $operator && 0 === $matched )
) {
$filtered[ $key ] = $obj;
}
}
$this->output = $filtered;
return $this->output;
}
/**
* Plucks a certain field out of each element in the input array.
*
* This has the same functionality and prototype of
* array_column() (PHP 5.5) but also supports objects.
*
* @since 4.7.0
*
* @param int|string $field Field to fetch from the object or array.
* @param int|string $index_key Optional. Field from the element to use as keys for the new array.
* Default null.
* @return array Array of found values. If `$index_key` is set, an array of found values with keys
* corresponding to `$index_key`. If `$index_key` is null, array keys from the original
* `$list` will be preserved in the results.
*/
public function pluck( $field, $index_key = null ) {
$newlist = array();
if ( ! $index_key ) {
/*
* This is simple. Could at some point wrap array_column()
* if we knew we had an array of arrays.
*/
foreach ( $this->output as $key => $value ) {
if ( is_object( $value ) ) {
$newlist[ $key ] = $value->$field;
} elseif ( is_array( $value ) ) {
$newlist[ $key ] = $value[ $field ];
} else {
_doing_it_wrong(
__METHOD__,
__( 'Values for the input array must be either objects or arrays.' ),
'6.2.0'
);
}
}
$this->output = $newlist;
return $this->output;
}
/*
* When index_key is not set for a particular item, push the value
* to the end of the stack. This is how array_column() behaves.
*/
foreach ( $this->output as $value ) {
if ( is_object( $value ) ) {
if ( isset( $value->$index_key ) ) {
$newlist[ $value->$index_key ] = $value->$field;
} else {
$newlist[] = $value->$field;
}
} elseif ( is_array( $value ) ) {
if ( isset( $value[ $index_key ] ) ) {
$newlist[ $value[ $index_key ] ] = $value[ $field ];
} else {
$newlist[] = $value[ $field ];
}
} else {
_doing_it_wrong(
__METHOD__,
__( 'Values for the input array must be either objects or arrays.' ),
'6.2.0'
);
}
}
$this->output = $newlist;
return $this->output;
}
/**
* Sorts the input array based on one or more orderby arguments.
*
* @since 4.7.0
*
* @param string|array $orderby Optional. Either the field name to order by or an array
* of multiple orderby fields as `$orderby => $order`.
* Default empty array.
* @param string $order Optional. Either 'ASC' or 'DESC'. Only used if `$orderby`
* is a string. Default 'ASC'.
* @param bool $preserve_keys Optional. Whether to preserve keys. Default false.
* @return array The sorted array.
*/
public function sort( $orderby = array(), $order = 'ASC', $preserve_keys = false ) {
if ( empty( $orderby ) ) {
return $this->output;
}
if ( is_string( $orderby ) ) {
$orderby = array( $orderby => $order );
}
foreach ( $orderby as $field => $direction ) {
$orderby[ $field ] = 'DESC' === strtoupper( $direction ) ? 'DESC' : 'ASC';
}
$this->orderby = $orderby;
if ( $preserve_keys ) {
uasort( $this->output, array( $this, 'sort_callback' ) );
} else {
usort( $this->output, array( $this, 'sort_callback' ) );
}
$this->orderby = array();
return $this->output;
}
/**
* Callback to sort an array by specific fields.
*
* @since 4.7.0
*
* @see WP_List_Util::sort()
*
* @param object|array $a One object to compare.
* @param object|array $b The other object to compare.
* @return int 0 if both objects equal. -1 if second object should come first, 1 otherwise.
*/
private function sort_callback( $a, $b ) {
if ( empty( $this->orderby ) ) {
return 0;
}
$a = (array) $a;
$b = (array) $b;
foreach ( $this->orderby as $field => $direction ) {
if ( ! isset( $a[ $field ] ) || ! isset( $b[ $field ] ) ) {
continue;
}
if ( $a[ $field ] == $b[ $field ] ) {
continue;
}
$results = 'DESC' === $direction ? array( 1, -1 ) : array( -1, 1 );
if ( is_numeric( $a[ $field ] ) && is_numeric( $b[ $field ] ) ) {
return ( $a[ $field ] < $b[ $field ] ) ? $results[0] : $results[1];
}
return 0 > strcmp( $a[ $field ], $b[ $field ] ) ? $results[0] : $results[1];
}
return 0;
}
}
<?php
/**
* Multisite upload handler.
*
* @since 3.0.0
*
* @package WordPress
* @subpackage Multisite
*/
define( 'MS_FILES_REQUEST', true );
define( 'SHORTINIT', true );
/** Load WordPress Bootstrap */
require_once dirname( __DIR__ ) . '/wp-load.php';
if ( ! is_multisite() ) {
die( 'Multisite support not enabled' );
}
ms_file_constants();
if ( '1' === $current_blog->archived || '1' === $current_blog->spam || '1' === $current_blog->deleted ) {
status_header( 404 );
die( '404 — File not found.' );
}
$file = rtrim( BLOGUPLOADDIR, '/' ) . '/' . str_replace( '..', '', $_GET['file'] );
if ( ! is_file( $file ) ) {
status_header( 404 );
die( '404 — File not found.' );
}
$mime = wp_check_filetype( $file );
if ( false === $mime['type'] && function_exists( 'mime_content_type' ) ) {
$mime['type'] = mime_content_type( $file );
}
if ( $mime['type'] ) {
$mimetype = $mime['type'];
} else {
$mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );
}
header( 'Content-Type: ' . $mimetype ); // Always send this.
if ( ! str_contains( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) ) {
header( 'Content-Length: ' . filesize( $file ) );
}
// Optional support for X-Sendfile and X-Accel-Redirect.
if ( WPMU_ACCEL_REDIRECT ) {
header( 'X-Accel-Redirect: ' . str_replace( WP_CONTENT_DIR, '', $file ) );
exit;
} elseif ( WPMU_SENDFILE ) {
header( 'X-Sendfile: ' . $file );
exit;
}
$wp_last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
$wp_etag = '"' . md5( $wp_last_modified ) . '"';
header( "Last-Modified: $wp_last_modified GMT" );
header( 'ETag: ' . $wp_etag );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );
// Support for conditional GET - use stripslashes() to avoid formatting.php dependency.
if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
$client_etag = stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] );
} else {
$client_etag = '';
}
if ( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
$client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
} else {
$client_last_modified = '';
}
// If string is empty, return 0. If not, attempt to parse into a timestamp.
$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
// Make a timestamp for our most recent modification.
$wp_modified_timestamp = strtotime( $wp_last_modified );
if ( ( $client_last_modified && $client_etag )
? ( ( $client_modified_timestamp >= $wp_modified_timestamp ) && ( $client_etag === $wp_etag ) )
: ( ( $client_modified_timestamp >= $wp_modified_timestamp ) || ( $client_etag === $wp_etag ) )
) {
status_header( 304 );
exit;
}
// If we made it this far, just serve the file.
readfile( $file );
flush();
<?php
/**
* WP_Theme_JSON_Schema class
*
* @package WordPress
* @subpackage Theme
* @since 5.9.0
*/
/**
* Class that migrates a given theme.json structure to the latest schema.
*
* This class is for internal core usage and is not supposed to be used by extenders (plugins and/or themes).
* This is a low-level API that may need to do breaking changes. Please,
* use get_global_settings, get_global_styles, and get_global_stylesheet instead.
*
* @since 5.9.0
* @access private
*/
#[AllowDynamicProperties]
class WP_Theme_JSON_Schema {
/**
* Maps old properties to their new location within the schema's settings.
* This will be applied at both the defaults and individual block levels.
*/
const V1_TO_V2_RENAMED_PATHS = array(
'border.customRadius' => 'border.radius',
'spacing.customMargin' => 'spacing.margin',
'spacing.customPadding' => 'spacing.padding',
'typography.customLineHeight' => 'typography.lineHeight',
);
/**
* Function that migrates a given theme.json structure to the last version.
*
* @since 5.9.0
* @since 6.6.0 Migrate up to v3 and add $origin parameter.
*
* @param array $theme_json The structure to migrate.
* @param string $origin Optional. What source of data this object represents.
* One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'.
* @return array The structure in the last version.
*/
public static function migrate( $theme_json, $origin = 'theme' ) {
if ( ! isset( $theme_json['version'] ) ) {
$theme_json = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
);
}
// Migrate each version in order starting with the current version.
switch ( $theme_json['version'] ) {
case 1:
$theme_json = self::migrate_v1_to_v2( $theme_json );
// Deliberate fall through. Once migrated to v2, also migrate to v3.
case 2:
$theme_json = self::migrate_v2_to_v3( $theme_json, $origin );
}
return $theme_json;
}
/**
* Removes the custom prefixes for a few properties
* that were part of v1:
*
* 'border.customRadius' => 'border.radius',
* 'spacing.customMargin' => 'spacing.margin',
* 'spacing.customPadding' => 'spacing.padding',
* 'typography.customLineHeight' => 'typography.lineHeight',
*
* @since 5.9.0
*
* @param array $old Data to migrate.
*
* @return array Data without the custom prefixes.
*/
private static function migrate_v1_to_v2( $old ) {
// Copy everything.
$new = $old;
// Overwrite the things that changed.
if ( isset( $old['settings'] ) ) {
$new['settings'] = self::rename_paths( $old['settings'], self::V1_TO_V2_RENAMED_PATHS );
}
// Set the new version.
$new['version'] = 2;
return $new;
}
/**
* Migrates from v2 to v3.
*
* - Sets settings.typography.defaultFontSizes to false if settings.typography.fontSizes are defined.
* - Sets settings.spacing.defaultSpacingSizes to false if settings.spacing.spacingSizes are defined.
* - Prevents settings.spacing.spacingSizes from merging with settings.spacing.spacingScale by
* unsetting spacingScale when spacingSizes are defined.
*
* @since 6.6.0
*
* @param array $old Data to migrate.
* @param string $origin What source of data this object represents.
* One of 'blocks', 'default', 'theme', or 'custom'.
* @return array Data with defaultFontSizes set to false.
*/
private static function migrate_v2_to_v3( $old, $origin ) {
// Copy everything.
$new = $old;
// Set the new version.
$new['version'] = 3;
/*
* Remaining changes do not need to be applied to the custom origin,
* as they should take on the value of the theme origin.
*/
if ( 'custom' === $origin ) {
return $new;
}
/*
* Even though defaultFontSizes and defaultSpacingSizes are new
* settings, we need to migrate them as they each control
* PRESETS_METADATA prevent_override values which were previously
* hardcoded to false. This only needs to happen when the theme provides
* fontSizes or spacingSizes as they could match the default ones and
* affect the generated CSS.
*/
if ( isset( $old['settings']['typography']['fontSizes'] ) ) {
$new['settings']['typography']['defaultFontSizes'] = false;
}
/*
* Similarly to defaultFontSizes, we need to migrate defaultSpacingSizes
* as it controls the PRESETS_METADATA prevent_override which was
* previously hardcoded to false. This only needs to happen when the
* theme provided spacing sizes via spacingSizes or spacingScale.
*/
if (
isset( $old['settings']['spacing']['spacingSizes'] ) ||
isset( $old['settings']['spacing']['spacingScale'] )
) {
$new['settings']['spacing']['defaultSpacingSizes'] = false;
}
/*
* In v3 spacingSizes is merged with the generated spacingScale sizes
* instead of completely replacing them. The v3 behavior is what was
* documented for the v2 schema, but the code never actually did work
* that way. Instead of surprising users with a behavior change two
* years after the fact at the same time as a v3 update is introduced,
* we'll continue using the "bugged" behavior for v2 themes. And treat
* the "bug fix" as a breaking change for v3.
*/
if ( isset( $old['settings']['spacing']['spacingSizes'] ) ) {
unset( $new['settings']['spacing']['spacingScale'] );
}
return $new;
}
/**
* Processes the settings subtree.
*
* @since 5.9.0
*
* @param array $settings Array to process.
* @param array $paths_to_rename Paths to rename.
*
* @return array The settings in the new format.
*/
private static function rename_paths( $settings, $paths_to_rename ) {
$new_settings = $settings;
// Process any renamed/moved paths within default settings.
self::rename_settings( $new_settings, $paths_to_rename );
// Process individual block settings.
if ( isset( $new_settings['blocks'] ) && is_array( $new_settings['blocks'] ) ) {
foreach ( $new_settings['blocks'] as &$block_settings ) {
self::rename_settings( $block_settings, $paths_to_rename );
}
}
return $new_settings;
}
/**
* Processes a settings array, renaming or moving properties.
*
* @since 5.9.0
*
* @param array $settings Reference to settings either defaults or an individual block's.
* @param array $paths_to_rename Paths to rename.
*/
private static function rename_settings( &$settings, $paths_to_rename ) {
foreach ( $paths_to_rename as $original => $renamed ) {
$original_path = explode( '.', $original );
$renamed_path = explode( '.', $renamed );
$current_value = _wp_array_get( $settings, $original_path, null );
if ( null !== $current_value ) {
_wp_array_set( $settings, $renamed_path, $current_value );
self::unset_setting_by_path( $settings, $original_path );
}
}
}
/**
* Removes a property from within the provided settings by its path.
*
* @since 5.9.0
*
* @param array $settings Reference to the current settings array.
* @param array $path Path to the property to be removed.
*/
private static function unset_setting_by_path( &$settings, $path ) {
$tmp_settings = &$settings;
$last_key = array_pop( $path );
foreach ( $path as $key ) {
$tmp_settings = &$tmp_settings[ $key ];
}
unset( $tmp_settings[ $last_key ] );
}
}
<?php
/**
* Core HTTP Request API
*
* Standardizes the HTTP requests for WordPress. Handles cookies, gzip encoding and decoding, chunk
* decoding, if HTTP 1.1 and various other difficult HTTP protocol implementations.
*
* @package WordPress
* @subpackage HTTP
*/
/**
* Returns the initialized WP_Http Object
*
* @since 2.7.0
* @access private
*
* @return WP_Http HTTP Transport object.
*/
function _wp_http_get_object() {
static $http = null;
if ( is_null( $http ) ) {
$http = new WP_Http();
}
return $http;
}
/**
* Retrieves the raw response from a safe HTTP request.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL, and every URL it redirects to, are validated with wp_http_validate_url()
* to avoid Server Side Request Forgery attacks (SSRF).
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
* @see wp_http_validate_url() For more information about how the URL is validated.
*
* @link https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_safe_remote_request( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
/**
* Retrieves the raw response from a safe HTTP request using the GET method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL, and every URL it redirects to, are validated with wp_http_validate_url()
* to avoid Server Side Request Forgery attacks (SSRF).
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
* @see wp_http_validate_url() For more information about how the URL is validated.
*
* @link https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_safe_remote_get( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->get( $url, $args );
}
/**
* Retrieves the raw response from a safe HTTP request using the POST method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL, and every URL it redirects to, are validated with wp_http_validate_url()
* to avoid Server Side Request Forgery attacks (SSRF).
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
* @see wp_http_validate_url() For more information about how the URL is validated.
*
* @link https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_safe_remote_post( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->post( $url, $args );
}
/**
* Retrieves the raw response from a safe HTTP request using the HEAD method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL, and every URL it redirects to, are validated with wp_http_validate_url()
* to avoid Server Side Request Forgery attacks (SSRF).
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
* @see wp_http_validate_url() For more information about how the URL is validated.
*
* @link https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_safe_remote_head( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->head( $url, $args );
}
/**
* Performs an HTTP request and returns its response.
*
* There are other API functions available which abstract away the HTTP method:
*
* - Default 'GET' for wp_remote_get()
* - Default 'POST' for wp_remote_post()
* - Default 'HEAD' for wp_remote_head()
*
* @since 2.7.0
*
* @see WP_Http::request() For information on default arguments.
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response array or a WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_remote_request( $url, $args = array() ) {
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
/**
* Performs an HTTP request using the GET method and returns its response.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_remote_get( $url, $args = array() ) {
$http = _wp_http_get_object();
return $http->get( $url, $args );
}
/**
* Performs an HTTP request using the POST method and returns its response.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_remote_post( $url, $args = array() ) {
$http = _wp_http_get_object();
return $http->post( $url, $args );
}
/**
* Performs an HTTP request using the HEAD method and returns its response.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* See WP_Http::request() for information on accepted arguments.
* @return array|WP_Error The response or WP_Error on failure.
* See WP_Http::request() for information on return value.
*/
function wp_remote_head( $url, $args = array() ) {
$http = _wp_http_get_object();
return $http->head( $url, $args );
}
/**
* Retrieves only the headers from the raw response.
*
* @since 2.7.0
* @since 4.6.0 Return value changed from an array to an WpOrg\Requests\Utility\CaseInsensitiveDictionary instance.
*
* @see \WpOrg\Requests\Utility\CaseInsensitiveDictionary
*
* @param array|WP_Error $response HTTP response.
* @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary|array The headers of the response, or empty array
* if incorrect parameter given.
*/
function wp_remote_retrieve_headers( $response ) {
if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) {
return array();
}
return $response['headers'];
}
/**
* Retrieves a single header by name from the raw response.
*
* @since 2.7.0
*
* @param array|WP_Error $response HTTP response.
* @param string $header Header name to retrieve value from.
* @return array|string The header(s) value(s). Array if multiple headers with the same name are retrieved.
* Empty string if incorrect parameter given, or if the header doesn't exist.
*/
function wp_remote_retrieve_header( $response, $header ) {
if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) {
return '';
}
if ( isset( $response['headers'][ $header ] ) ) {
return $response['headers'][ $header ];
}
return '';
}
/**
* Retrieves only the response code from the raw response.
*
* Will return an empty string if incorrect parameter value is given.
*
* @since 2.7.0
*
* @param array|WP_Error $response HTTP response.
* @return int|string The response code as an integer. Empty string if incorrect parameter given.
*/
function wp_remote_retrieve_response_code( $response ) {
if ( is_wp_error( $response ) || ! isset( $response['response'] ) || ! is_array( $response['response'] ) ) {
return '';
}
return $response['response']['code'];
}
/**
* Retrieves only the response message from the raw response.
*
* Will return an empty string if incorrect parameter value is given.
*
* @since 2.7.0
*
* @param array|WP_Error $response HTTP response.
* @return string The response message. Empty string if incorrect parameter given.
*/
function wp_remote_retrieve_response_message( $response ) {
if ( is_wp_error( $response ) || ! isset( $response['response'] ) || ! is_array( $response['response'] ) ) {
return '';
}
return $response['response']['message'];
}
/**
* Retrieves only the body from the raw response.
*
* @since 2.7.0
*
* @param array|WP_Error $response HTTP response.
* @return string The body of the response. Empty string if no body or incorrect parameter given.
*/
function wp_remote_retrieve_body( $response ) {
if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
return '';
}
return $response['body'];
}
/**
* Retrieves only the cookies from the raw response.
*
* @since 4.4.0
*
* @param array|WP_Error $response HTTP response.
* @return WP_Http_Cookie[] An array of `WP_Http_Cookie` objects from the response.
* Empty array if there are none, or the response is a WP_Error.
*/
function wp_remote_retrieve_cookies( $response ) {
if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) {
return array();
}
return $response['cookies'];
}
/**
* Retrieves a single cookie by name from the raw response.
*
* @since 4.4.0
*
* @param array|WP_Error $response HTTP response.
* @param string $name The name of the cookie to retrieve.
* @return WP_Http_Cookie|string The `WP_Http_Cookie` object, or empty string
* if the cookie is not present in the response.
*/
function wp_remote_retrieve_cookie( $response, $name ) {
$cookies = wp_remote_retrieve_cookies( $response );
if ( empty( $cookies ) ) {
return '';
}
foreach ( $cookies as $cookie ) {
if ( $cookie->name === $name ) {
return $cookie;
}
}
return '';
}
/**
* Retrieves a single cookie's value by name from the raw response.
*
* @since 4.4.0
*
* @param array|WP_Error $response HTTP response.
* @param string $name The name of the cookie to retrieve.
* @return string The value of the cookie, or empty string
* if the cookie is not present in the response.
*/
function wp_remote_retrieve_cookie_value( $response, $name ) {
$cookie = wp_remote_retrieve_cookie( $response, $name );
if ( ! ( $cookie instanceof WP_Http_Cookie ) ) {
return '';
}
return $cookie->value;
}
/**
* Determines if there is an HTTP Transport that can process this request.
*
* @since 3.2.0
*
* @param array $capabilities Array of capabilities to test or a wp_remote_request() $args array.
* @param string $url Optional. If given, will check if the URL requires SSL and adds
* that requirement to the capabilities array.
*
* @return bool
*/
function wp_http_supports( $capabilities = array(), $url = null ) {
$capabilities = wp_parse_args( $capabilities );
$count = count( $capabilities );
// If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array.
if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) === $count ) {
$capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
}
if ( $url && ! isset( $capabilities['ssl'] ) ) {
$scheme = parse_url( $url, PHP_URL_SCHEME );
if ( 'https' === $scheme || 'ssl' === $scheme ) {
$capabilities['ssl'] = true;
}
}
return WpOrg\Requests\Requests::has_capabilities( $capabilities );
}
/**
* Gets the HTTP Origin of the current request.
*
* @since 3.4.0
*
* @return string URL of the origin. Empty string if no origin.
*/
function get_http_origin() {
$origin = '';
if ( ! empty( $_SERVER['HTTP_ORIGIN'] ) ) {
$origin = $_SERVER['HTTP_ORIGIN'];
}
/**
* Changes the origin of an HTTP request.
*
* @since 3.4.0
*
* @param string $origin The original origin for the request.
*/
return apply_filters( 'http_origin', $origin );
}
/**
* Retrieves list of allowed HTTP origins.
*
* @since 3.4.0
*
* @return string[] Array of origin URLs.
*/
function get_allowed_http_origins() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
// @todo Preserve port?
$allowed_origins = array_unique(
array(
'http://' . $admin_origin['host'],
'https://' . $admin_origin['host'],
'http://' . $home_origin['host'],
'https://' . $home_origin['host'],
)
);
/**
* Changes the origin types allowed for HTTP requests.
*
* @since 3.4.0
*
* @param string[] $allowed_origins {
* Array of default allowed HTTP origins.
*
* @type string $0 Non-secure URL for admin origin.
* @type string $1 Secure URL for admin origin.
* @type string $2 Non-secure URL for home origin.
* @type string $3 Secure URL for home origin.
* }
*/
return apply_filters( 'allowed_http_origins', $allowed_origins );
}
/**
* Determines if the HTTP origin is an authorized one.
*
* @since 3.4.0
*
* @param string|null $origin Origin URL. If not provided, the value of get_http_origin() is used.
* @return string Origin URL if allowed, empty string if not.
*/
function is_allowed_http_origin( $origin = null ) {
$origin_arg = $origin;
if ( null === $origin ) {
$origin = get_http_origin();
}
if ( $origin && ! in_array( $origin, get_allowed_http_origins(), true ) ) {
$origin = '';
}
/**
* Changes the allowed HTTP origin result.
*
* @since 3.4.0
*
* @param string $origin Origin URL if allowed, empty string if not.
* @param string $origin_arg Original origin string passed into is_allowed_http_origin function.
*/
return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
}
/**
* Sends Access-Control-Allow-Origin and related headers if the current request
* is from an allowed origin.
*
* If the request is an OPTIONS request, the script exits with either access
* control headers sent, or a 403 response if the origin is not allowed. For
* other request methods, you will receive a return value.
*
* @since 3.4.0
*
* @return string|false Returns the origin URL if headers are sent. Returns false
* if headers are not sent.
*/
function send_origin_headers() {
$origin = get_http_origin();
if ( is_allowed_http_origin( $origin ) ) {
header( 'Access-Control-Allow-Origin: ' . $origin );
header( 'Access-Control-Allow-Credentials: true' );
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
exit;
}
return $origin;
}
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
status_header( 403 );
exit;
}
return false;
}
/**
* Validates a URL for safe use in the HTTP API.
*
* Examples of URLs that are considered unsafe:
*
* - ftp://example.com/caniload.php - Invalid protocol - only http and https are allowed.
* - http:///example.com/caniload.php - Malformed URL.
* - http://user:pass@example.com/caniload.php - Login information.
* - http://example.invalid/caniload.php - Invalid hostname, as the IP cannot be looked up in DNS.
*
* Examples of URLs that are considered unsafe by default:
*
* - http://192.168.0.1/caniload.php - IPs from LAN networks.
* This can be changed with the {@see 'http_request_host_is_external'} filter.
* - http://198.143.164.252:81/caniload.php - By default, only 80, 443, and 8080 ports are allowed.
* This can be changed with the {@see 'http_allowed_safe_ports'} filter.
*
* @since 3.5.2
*
* @param string $url Request URL.
* @return string|false URL or false on failure.
*/
function wp_http_validate_url( $url ) {
if ( ! is_string( $url ) || '' === $url || is_numeric( $url ) ) {
return false;
}
$original_url = $url;
$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) ) {
return false;
}
$parsed_url = parse_url( $url );
if ( ! $parsed_url || empty( $parsed_url['host'] ) ) {
return false;
}
if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) ) {
return false;
}
if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) ) {
return false;
}
$parsed_home = parse_url( get_option( 'home' ) );
$same_host = isset( $parsed_home['host'] ) && strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
$host = trim( $parsed_url['host'], '.' );
if ( ! $same_host ) {
if ( preg_match( '#^(([1-9]?\d|1\d\d|25[0-5]|2[0-4]\d)\.){3}([1-9]?\d|1\d\d|25[0-5]|2[0-4]\d)$#', $host ) ) {
$ip = $host;
} else {
$ip = gethostbyname( $host );
if ( $ip === $host ) { // Error condition for gethostbyname().
return false;
}
}
if ( $ip ) {
$parts = array_map( 'intval', explode( '.', $ip ) );
if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0]
|| ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
|| ( 192 === $parts[0] && 168 === $parts[1] )
) {
// If host appears local, reject unless specifically allowed.
/**
* Checks if HTTP request is external or not.
*
* Allows to change and allow external requests for the HTTP request.
*
* @since 3.6.0
*
* @param bool $external Whether HTTP request is external or not.
* @param string $host Host name of the requested URL.
* @param string $url Requested URL.
*/
if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) ) {
return false;
}
}
}
}
if ( empty( $parsed_url['port'] ) ) {
return $url;
}
$port = $parsed_url['port'];
/**
* Controls the list of ports considered safe in HTTP API.
*
* Allows to change and allow external requests for the HTTP request.
*
* @since 5.9.0
*
* @param int[] $allowed_ports Array of integers for valid ports.
* @param string $host Host name of the requested URL.
* @param string $url Requested URL.
*/
$allowed_ports = apply_filters( 'http_allowed_safe_ports', array( 80, 443, 8080 ), $host, $url );
if ( is_array( $allowed_ports ) && in_array( $port, $allowed_ports, true ) ) {
return $url;
}
if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port ) {
return $url;
}
return false;
}
/**
* Marks allowed redirect hosts safe for HTTP requests as well.
*
* Attached to the {@see 'http_request_host_is_external'} filter.
*
* @since 3.6.0
*
* @param bool $is_external
* @param string $host
* @return bool
*/
function allowed_http_request_hosts( $is_external, $host ) {
if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) ) {
$is_external = true;
}
return $is_external;
}
/**
* Adds any domain in a multisite installation for safe HTTP requests to the
* allowed list.
*
* Attached to the {@see 'http_request_host_is_external'} filter.
*
* @since 3.6.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param bool $is_external
* @param string $host
* @return bool
*/
function ms_allowed_http_request_hosts( $is_external, $host ) {
global $wpdb;
static $queried = array();
if ( $is_external ) {
return $is_external;
}
if ( get_network()->domain === $host ) {
return true;
}
if ( isset( $queried[ $host ] ) ) {
return $queried[ $host ];
}
$queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
return $queried[ $host ];
}
/**
* A wrapper for PHP's parse_url() function that handles consistency in the return values
* across PHP versions.
*
* Across various PHP versions, schemeless URLs containing a ":" in the query
* are being handled inconsistently. This function works around those differences.
*
* @since 4.4.0
* @since 4.7.0 The `$component` parameter was added for parity with PHP's `parse_url()`.
*
* @link https://www.php.net/manual/en/function.parse-url.php
*
* @param string $url The URL to parse.
* @param int $component The specific component to retrieve. Use one of the PHP
* predefined constants to specify which one.
* Defaults to -1 (= return all parts as an array).
* @return mixed False on parse failure; Array of URL components on success;
* When a specific component has been requested: null if the component
* doesn't exist in the given URL; a string or - in the case of
* PHP_URL_PORT - integer when it does. See parse_url()'s return values.
*/
function wp_parse_url( $url, $component = -1 ) {
$to_unset = array();
$url = (string) $url;
if ( str_starts_with( $url, '//' ) ) {
$to_unset[] = 'scheme';
$url = 'placeholder:' . $url;
} elseif ( str_starts_with( $url, '/' ) ) {
$to_unset[] = 'scheme';
$to_unset[] = 'host';
$url = 'placeholder://placeholder' . $url;
}
$parts = parse_url( $url );
if ( false === $parts ) {
// Parsing failure.
return $parts;
}
// Remove the placeholder values.
foreach ( $to_unset as $key ) {
unset( $parts[ $key ] );
}
return _get_component_from_parsed_url_array( $parts, $component );
}
/**
* Retrieves a specific component from a parsed URL array.
*
* @internal
*
* @since 4.7.0
* @access private
*
* @link https://www.php.net/manual/en/function.parse-url.php
*
* @param array|false $url_parts The parsed URL. Can be false if the URL failed to parse.
* @param int $component The specific component to retrieve. Use one of the PHP
* predefined constants to specify which one.
* Defaults to -1 (= return all parts as an array).
* @return mixed False on parse failure; Array of URL components on success;
* When a specific component has been requested: null if the component
* doesn't exist in the given URL; a string or - in the case of
* PHP_URL_PORT - integer when it does. See parse_url()'s return values.
*/
function _get_component_from_parsed_url_array( $url_parts, $component = -1 ) {
if ( -1 === $component ) {
return $url_parts;
}
$key = _wp_translate_php_url_constant_to_key( $component );
if ( false !== $key && is_array( $url_parts ) && isset( $url_parts[ $key ] ) ) {
return $url_parts[ $key ];
} else {
return null;
}
}
/**
* Translates a PHP_URL_* constant to the named array keys PHP uses.
*
* @internal
*
* @since 4.7.0
* @access private
*
* @link https://www.php.net/manual/en/url.constants.php
*
* @param int $constant PHP_URL_* constant.
* @return string|false The named key or false.
*/
function _wp_translate_php_url_constant_to_key( $constant ) {
$translation = array(
PHP_URL_SCHEME => 'scheme',
PHP_URL_HOST => 'host',
PHP_URL_PORT => 'port',
PHP_URL_USER => 'user',
PHP_URL_PASS => 'pass',
PHP_URL_PATH => 'path',
PHP_URL_QUERY => 'query',
PHP_URL_FRAGMENT => 'fragment',
);
if ( isset( $translation[ $constant ] ) ) {
return $translation[ $constant ];
} else {
return false;
}
}
<?php
/**
* IXR - The Incutio XML-RPC Library
*
* Copyright (c) 2010, Incutio Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of Incutio Ltd. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @package IXR
* @since 1.5.0
*
* @copyright Incutio Ltd 2010 (http://www.incutio.com)
* @version 1.7.4 7th September 2010
* @author Simon Willison
* @link http://scripts.incutio.com/xmlrpc/ Site/manual
* @license http://www.opensource.org/licenses/bsd-license.php BSD
*/
// Don't load directly.
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
require_once ABSPATH . WPINC . '/IXR/class-IXR-server.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-base64.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-client.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-clientmulticall.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-date.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-error.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-introspectionserver.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-message.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-request.php';
require_once ABSPATH . WPINC . '/IXR/class-IXR-value.php';<?php
/**
* Taxonomy API: WP_Taxonomy class
*
* @package WordPress
* @subpackage Taxonomy
* @since 4.7.0
*/
/**
* Core class used for interacting with taxonomies.
*
* @since 4.7.0
*/
#[AllowDynamicProperties]
final class WP_Taxonomy {
/**
* Taxonomy key.
*
* @since 4.7.0
* @var string
*/
public $name;
/**
* Name of the taxonomy shown in the menu. Usually plural.
*
* @since 4.7.0
* @var string
*/
public $label;
/**
* Labels object for this taxonomy.
*
* If not set, tag labels are inherited for non-hierarchical types
* and category labels for hierarchical ones.
*
* @see get_taxonomy_labels()
*
* @since 4.7.0
* @var stdClass
*/
public $labels;
/**
* Default labels.
*
* @since 6.0.0
* @var (string|null)[][] $default_labels
*/
protected static $default_labels = array();
/**
* A short descriptive summary of what the taxonomy is for.
*
* @since 4.7.0
* @var string
*/
public $description = '';
/**
* Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users.
*
* @since 4.7.0
* @var bool
*/
public $public = true;
/**
* Whether the taxonomy is publicly queryable.
*
* @since 4.7.0
* @var bool
*/
public $publicly_queryable = true;
/**
* Whether the taxonomy is hierarchical.
*
* @since 4.7.0
* @var bool
*/
public $hierarchical = false;
/**
* Whether to generate and allow a UI for managing terms in this taxonomy in the admin.
*
* @since 4.7.0
* @var bool
*/
public $show_ui = true;
/**
* Whether to show the taxonomy in the admin menu.
*
* If true, the taxonomy is shown as a submenu of the object type menu. If false, no menu is shown.
*
* @since 4.7.0
* @var bool
*/
public $show_in_menu = true;
/**
* Whether the taxonomy is available for selection in navigation menus.
*
* @since 4.7.0
* @var bool
*/
public $show_in_nav_menus = true;
/**
* Whether to list the taxonomy in the tag cloud widget controls.
*
* @since 4.7.0
* @var bool
*/
public $show_tagcloud = true;
/**
* Whether to show the taxonomy in the quick/bulk edit panel.
*
* @since 4.7.0
* @var bool
*/
public $show_in_quick_edit = true;
/**
* Whether to display a column for the taxonomy on its post type listing screens.
*
* @since 4.7.0
* @var bool
*/
public $show_admin_column = false;
/**
* The callback function for the meta box display.
*
* @since 4.7.0
* @var bool|callable
*/
public $meta_box_cb = null;
/**
* The callback function for sanitizing taxonomy data saved from a meta box.
*
* @since 5.1.0
* @var callable
*/
public $meta_box_sanitize_cb = null;
/**
* An array of object types this taxonomy is registered for.
*
* @since 4.7.0
* @var string[]
*/
public $object_type = null;
/**
* Capabilities for this taxonomy.
*
* @since 4.7.0
* @var stdClass
*/
public $cap;
/**
* Rewrites information for this taxonomy.
*
* @since 4.7.0
* @var array|false
*/
public $rewrite;
/**
* Query var string for this taxonomy.
*
* @since 4.7.0
* @var string|false
*/
public $query_var;
/**
* Function that will be called when the count is updated.
*
* @since 4.7.0
* @var callable
*/
public $update_count_callback;
/**
* Whether this taxonomy should appear in the REST API.
*
* Default false. If true, standard endpoints will be registered with
* respect to $rest_base and $rest_controller_class.
*
* @since 4.7.4
* @var bool $show_in_rest
*/
public $show_in_rest;
/**
* The base path for this taxonomy's REST API endpoints.
*
* @since 4.7.4
* @var string|bool $rest_base
*/
public $rest_base;
/**
* The namespace for this taxonomy's REST API endpoints.
*
* @since 5.9.0
* @var string|bool $rest_namespace
*/
public $rest_namespace;
/**
* The controller for this taxonomy's REST API endpoints.
*
* Custom controllers must extend WP_REST_Controller.
*
* @since 4.7.4
* @var string|bool $rest_controller_class
*/
public $rest_controller_class;
/**
* The controller instance for this taxonomy's REST API endpoints.
*
* Lazily computed. Should be accessed using {@see WP_Taxonomy::get_rest_controller()}.
*
* @since 5.5.0
* @var WP_REST_Controller $rest_controller
*/
public $rest_controller;
/**
* The default term name for this taxonomy. If you pass an array you have
* to set 'name' and optionally 'slug' and 'description'.
*
* @since 5.5.0
* @var array|string
*/
public $default_term;
/**
* Whether terms in this taxonomy should be sorted in the order they are provided to `wp_set_object_terms()`.
*
* Use this in combination with `'orderby' => 'term_order'` when fetching terms.
*
* @since 2.5.0
* @var bool|null
*/
public $sort = null;
/**
* Array of arguments to automatically use inside `wp_get_object_terms()` for this taxonomy.
*
* @since 2.6.0
* @var array|null
*/
public $args = null;
/**
* Whether it is a built-in taxonomy.
*
* @since 4.7.0
* @var bool
*/
public $_builtin;
/**
* Constructor.
*
* See the register_taxonomy() function for accepted arguments for `$args`.
*
* @since 4.7.0
*
* @param string $taxonomy Taxonomy key, must not exceed 32 characters.
* @param array|string $object_type Name of the object type for the taxonomy object.
* @param array|string $args Optional. Array or query string of arguments for registering a taxonomy.
* See register_taxonomy() for information on accepted arguments.
* Default empty array.
*/
public function __construct( $taxonomy, $object_type, $args = array() ) {
$this->name = $taxonomy;
$this->set_props( $object_type, $args );
}
/**
* Sets taxonomy properties.
*
* See the register_taxonomy() function for accepted arguments for `$args`.
*
* @since 4.7.0
*
* @param string|string[] $object_type Name or array of names of the object types for the taxonomy.
* @param array|string $args Array or query string of arguments for registering a taxonomy.
*/
public function set_props( $object_type, $args ) {
$args = wp_parse_args( $args );
/**
* Filters the arguments for registering a taxonomy.
*
* @since 4.4.0
*
* @param array $args Array of arguments for registering a taxonomy.
* See the register_taxonomy() function for accepted arguments.
* @param string $taxonomy Taxonomy key.
* @param string[] $object_type Array of names of object types for the taxonomy.
*/
$args = apply_filters( 'register_taxonomy_args', $args, $this->name, (array) $object_type );
$taxonomy = $this->name;
/**
* Filters the arguments for registering a specific taxonomy.
*
* The dynamic portion of the filter name, `$taxonomy`, refers to the taxonomy key.
*
* Possible hook names include:
*
* - `register_category_taxonomy_args`
* - `register_post_tag_taxonomy_args`
*
* @since 6.0.0
*
* @param array $args Array of arguments for registering a taxonomy.
* See the register_taxonomy() function for accepted arguments.
* @param string $taxonomy Taxonomy key.
* @param string[] $object_type Array of names of object types for the taxonomy.
*/
$args = apply_filters( "register_{$taxonomy}_taxonomy_args", $args, $this->name, (array) $object_type );
$defaults = array(
'labels' => array(),
'description' => '',
'public' => true,
'publicly_queryable' => null,
'hierarchical' => false,
'show_ui' => null,
'show_in_menu' => null,
'show_in_nav_menus' => null,
'show_tagcloud' => null,
'show_in_quick_edit' => null,
'show_admin_column' => false,
'meta_box_cb' => null,
'meta_box_sanitize_cb' => null,
'capabilities' => array(),
'rewrite' => true,
'query_var' => $this->name,
'update_count_callback' => '',
'show_in_rest' => false,
'rest_base' => false,
'rest_namespace' => false,
'rest_controller_class' => false,
'default_term' => null,
'sort' => null,
'args' => null,
'_builtin' => false,
);
$args = array_merge( $defaults, $args );
// If not set, default to the setting for 'public'.
if ( null === $args['publicly_queryable'] ) {
$args['publicly_queryable'] = $args['public'];
}
if ( false !== $args['query_var'] && ( is_admin() || false !== $args['publicly_queryable'] ) ) {
if ( true === $args['query_var'] ) {
$args['query_var'] = $this->name;
} else {
$args['query_var'] = sanitize_title_with_dashes( $args['query_var'] );
}
} else {
// Force 'query_var' to false for non-public taxonomies.
$args['query_var'] = false;
}
if ( false !== $args['rewrite'] && ( is_admin() || get_option( 'permalink_structure' ) ) ) {
$args['rewrite'] = wp_parse_args(
$args['rewrite'],
array(
'with_front' => true,
'hierarchical' => false,
'ep_mask' => EP_NONE,
)
);
if ( empty( $args['rewrite']['slug'] ) ) {
$args['rewrite']['slug'] = sanitize_title_with_dashes( $this->name );
}
}
// If not set, default to the setting for 'public'.
if ( null === $args['show_ui'] ) {
$args['show_ui'] = $args['public'];
}
// If not set, default to the setting for 'show_ui'.
if ( null === $args['show_in_menu'] || ! $args['show_ui'] ) {
$args['show_in_menu'] = $args['show_ui'];
}
// If not set, default to the setting for 'public'.
if ( null === $args['show_in_nav_menus'] ) {
$args['show_in_nav_menus'] = $args['public'];
}
// If not set, default to the setting for 'show_ui'.
if ( null === $args['show_tagcloud'] ) {
$args['show_tagcloud'] = $args['show_ui'];
}
// If not set, default to the setting for 'show_ui'.
if ( null === $args['show_in_quick_edit'] ) {
$args['show_in_quick_edit'] = $args['show_ui'];
}
// If not set, default rest_namespace to wp/v2 if show_in_rest is true.
if ( false === $args['rest_namespace'] && ! empty( $args['show_in_rest'] ) ) {
$args['rest_namespace'] = 'wp/v2';
}
$default_caps = array(
'manage_terms' => 'manage_categories',
'edit_terms' => 'manage_categories',
'delete_terms' => 'manage_categories',
'assign_terms' => 'edit_posts',
);
$args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] );
unset( $args['capabilities'] );
$args['object_type'] = array_unique( (array) $object_type );
// If not set, use the default meta box.
if ( null === $args['meta_box_cb'] ) {
if ( $args['hierarchical'] ) {
$args['meta_box_cb'] = 'post_categories_meta_box';
} else {
$args['meta_box_cb'] = 'post_tags_meta_box';
}
}
$args['name'] = $this->name;
// Default meta box sanitization callback depends on the value of 'meta_box_cb'.
if ( null === $args['meta_box_sanitize_cb'] ) {
switch ( $args['meta_box_cb'] ) {
case 'post_categories_meta_box':
$args['meta_box_sanitize_cb'] = 'taxonomy_meta_box_sanitize_cb_checkboxes';
break;
case 'post_tags_meta_box':
default:
$args['meta_box_sanitize_cb'] = 'taxonomy_meta_box_sanitize_cb_input';
break;
}
}
// Default taxonomy term.
if ( ! empty( $args['default_term'] ) ) {
if ( ! is_array( $args['default_term'] ) ) {
$args['default_term'] = array( 'name' => $args['default_term'] );
}
$args['default_term'] = wp_parse_args(
$args['default_term'],
array(
'name' => '',
'slug' => '',
'description' => '',
)
);
}
foreach ( $args as $property_name => $property_value ) {
$this->$property_name = $property_value;
}
$this->labels = get_taxonomy_labels( $this );
$this->label = $this->labels->name;
}
/**
* Adds the necessary rewrite rules for the taxonomy.
*
* @since 4.7.0
*
* @global WP $wp Current WordPress environment instance.
*/
public function add_rewrite_rules() {
/* @var WP $wp */
global $wp;
// Non-publicly queryable taxonomies should not register query vars, except in the admin.
if ( false !== $this->query_var && $wp ) {
$wp->add_query_var( $this->query_var );
}
if ( false !== $this->rewrite && ( is_admin() || get_option( 'permalink_structure' ) ) ) {
if ( $this->hierarchical && $this->rewrite['hierarchical'] ) {
$tag = '(.+?)';
} else {
$tag = '([^/]+)';
}
add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" );
add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite );
}
}
/**
* Removes any rewrite rules, permastructs, and rules for the taxonomy.
*
* @since 4.7.0
*
* @global WP $wp Current WordPress environment instance.
*/
public function remove_rewrite_rules() {
/* @var WP $wp */
global $wp;
// Remove query var.
if ( false !== $this->query_var ) {
$wp->remove_query_var( $this->query_var );
}
// Remove rewrite tags and permastructs.
if ( false !== $this->rewrite ) {
remove_rewrite_tag( "%$this->name%" );
remove_permastruct( $this->name );
}
}
/**
* Registers the ajax callback for the meta box.
*
* @since 4.7.0
*/
public function add_hooks() {
add_filter( 'wp_ajax_add-' . $this->name, '_wp_ajax_add_hierarchical_term' );
}
/**
* Removes the ajax callback for the meta box.
*
* @since 4.7.0
*/
public function remove_hooks() {
remove_filter( 'wp_ajax_add-' . $this->name, '_wp_ajax_add_hierarchical_term' );
}
/**
* Gets the REST API controller for this taxonomy.
*
* Will only instantiate the controller class once per request.
*
* @since 5.5.0
*
* @return WP_REST_Controller|null The controller instance, or null if the taxonomy
* is set not to show in rest.
*/
public function get_rest_controller() {
if ( ! $this->show_in_rest ) {
return null;
}
$class = $this->rest_controller_class ? $this->rest_controller_class : WP_REST_Terms_Controller::class;
if ( ! class_exists( $class ) ) {
return null;
}
if ( ! is_subclass_of( $class, WP_REST_Controller::class ) ) {
return null;
}
if ( ! $this->rest_controller ) {
$this->rest_controller = new $class( $this->name );
}
if ( ! ( $this->rest_controller instanceof $class ) ) {
return null;
}
return $this->rest_controller;
}
/**
* Returns the default labels for taxonomies.
*
* @since 6.0.0
*
* @return (string|null)[][] The default labels for taxonomies.
*/
public static function get_default_labels() {
if ( ! empty( self::$default_labels ) ) {
return self::$default_labels;
}
$name_field_description = __( 'The name is how it appears on your site.' );
$slug_field_description = __( 'The “slug” is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.' );
$parent_field_description = __( 'Assign a parent term to create a hierarchy. The term Jazz, for example, would be the parent of Bebop and Big Band.' );
$desc_field_description = __( 'The description is not prominent by default; however, some themes may show it.' );
self::$default_labels = array(
'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
'popular_items' => array( __( 'Popular Tags' ), null ),
'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
'parent_item' => array( null, __( 'Parent Category' ) ),
'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
'name_field_description' => array( $name_field_description, $name_field_description ),
'slug_field_description' => array( $slug_field_description, $slug_field_description ),
'parent_field_description' => array( null, $parent_field_description ),
'desc_field_description' => array( $desc_field_description, $desc_field_description ),
'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
'add_new_item' => array( __( 'Add Tag' ), __( 'Add Category' ) ),
'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ),
'filter_by_item' => array( null, __( 'Filter by category' ) ),
'items_list_navigation' => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
'items_list' => array( __( 'Tags list' ), __( 'Categories list' ) ),
/* translators: Tab heading when selecting from the most used terms. */
'most_used' => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ),
'back_to_items' => array( __( '← Go to Tags' ), __( '← Go to Categories' ) ),
'item_link' => array(
_x( 'Tag Link', 'navigation link block title' ),
_x( 'Category Link', 'navigation link block title' ),
),
'item_link_description' => array(
_x( 'A link to a tag.', 'navigation link block description' ),
_x( 'A link to a category.', 'navigation link block description' ),
),
);
return self::$default_labels;
}
/**
* Resets the cache for the default labels.
*
* @since 6.0.0
*/
public static function reset_default_labels() {
self::$default_labels = array();
}
}
<?php
/**
* Object Cache API: WP_Object_Cache class
*
* @package WordPress
* @subpackage Cache
* @since 5.4.0
*/
/**
* Core class that implements an object cache.
*
* The WordPress Object Cache is used to save on trips to the database. The
* Object Cache stores all of the cache data to memory and makes the cache
* contents available by using a key, which is used to name and later retrieve
* the cache contents.
*
* The Object Cache can be replaced by other caching mechanisms by placing files
* in the wp-content folder which is looked at in wp-settings. If that file
* exists, then this file will not be included.
*
* @since 2.0.0
*/
#[AllowDynamicProperties]
class WP_Object_Cache {
/**
* Holds the cached objects.
*
* @since 2.0.0
* @var array
*/
private $cache = array();
/**
* The amount of times the cache data was already stored in the cache.
*
* @since 2.5.0
* @var int
*/
public $cache_hits = 0;
/**
* Amount of times the cache did not have the request in cache.
*
* @since 2.0.0
* @var int
*/
public $cache_misses = 0;
/**
* List of global cache groups.
*
* @since 3.0.0
* @var string[]
*/
protected $global_groups = array();
/**
* The blog prefix to prepend to keys in non-global groups.
*
* @since 3.5.0
* @var string
*/
private $blog_prefix;
/**
* Holds the value of is_multisite().
*
* @since 3.5.0
* @var bool
*/
private $multisite;
/**
* Sets up object properties.
*
* @since 2.0.8
*/
public function __construct() {
$this->multisite = is_multisite();
$this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';
}
/**
* Makes private properties readable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to get.
* @return mixed Property.
*/
public function __get( $name ) {
return $this->$name;
}
/**
* Makes private properties settable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to set.
* @param mixed $value Property value.
*/
public function __set( $name, $value ) {
$this->$name = $value;
}
/**
* Makes private properties checkable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to check if set.
* @return bool Whether the property is set.
*/
public function __isset( $name ) {
return isset( $this->$name );
}
/**
* Makes private properties un-settable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Property to unset.
*/
public function __unset( $name ) {
unset( $this->$name );
}
/**
* Serves as a utility function to determine whether a key is valid.
*
* @since 6.1.0
*
* @param int|string $key Cache key to check for validity.
* @return bool Whether the key is valid.
*/
protected function is_valid_key( $key ) {
if ( is_int( $key ) ) {
return true;
}
if ( is_string( $key ) && trim( $key ) !== '' ) {
return true;
}
$type = gettype( $key );
if ( ! function_exists( '__' ) ) {
wp_load_translations_early();
}
$message = is_string( $key )
? __( 'Cache key must not be an empty string.' )
/* translators: %s: The type of the given cache key. */
: sprintf( __( 'Cache key must be an integer or a non-empty string, %s given.' ), $type );
_doing_it_wrong(
sprintf( '%s::%s', __CLASS__, debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 )[1]['function'] ),
$message,
'6.1.0'
);
return false;
}
/**
* Serves as a utility function to determine whether a key exists in the cache.
*
* @since 3.4.0
*
* @param int|string $key Cache key to check for existence.
* @param string $group Cache group for the key existence check.
* @return bool Whether the key exists in the cache for the given group.
*/
protected function _exists( $key, $group ) {
return isset( $this->cache[ $group ] ) && ( isset( $this->cache[ $group ][ $key ] ) || array_key_exists( $key, $this->cache[ $group ] ) );
}
/**
* Adds data to the cache if it doesn't already exist.
*
* @since 2.0.0
*
* @uses WP_Object_Cache::_exists() Checks to see if the cache already has data.
* @uses WP_Object_Cache::set() Sets the data after the checking the cache
* contents existence.
*
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool True on success, false if cache key and group already exist.
*/
public function add( $key, $data, $group = 'default', $expire = 0 ) {
if ( wp_suspend_cache_addition() ) {
return false;
}
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
$id = $key;
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$id = $this->blog_prefix . $key;
}
if ( $this->_exists( $id, $group ) ) {
return false;
}
return $this->set( $key, $data, $group, (int) $expire );
}
/**
* Adds multiple values to the cache in one call.
*
* @since 6.0.0
*
* @param array $data Array of keys and values to be added.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool[] Array of return values, grouped by key. Each value is either
* true on success, or false if cache key and group already exist.
*/
public function add_multiple( array $data, $group = '', $expire = 0 ) {
$values = array();
foreach ( $data as $key => $value ) {
$values[ $key ] = $this->add( $key, $value, $group, $expire );
}
return $values;
}
/**
* Replaces the contents in the cache, if contents already exist.
*
* @since 2.0.0
*
* @see WP_Object_Cache::set()
*
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool True if contents were replaced, false if original value does not exist.
*/
public function replace( $key, $data, $group = 'default', $expire = 0 ) {
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
$id = $key;
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$id = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $id, $group ) ) {
return false;
}
return $this->set( $key, $data, $group, (int) $expire );
}
/**
* Sets the data contents into the cache.
*
* The cache contents are grouped by the $group parameter followed by the
* $key. This allows for duplicate IDs in unique groups. Therefore, naming of
* the group should be used with care and should follow normal function
* naming guidelines outside of core WordPress usage.
*
* The $expire parameter is not used, because the cache will automatically
* expire for each time a page is accessed and PHP finishes. The method is
* more for cache plugins which use files.
*
* @since 2.0.0
* @since 6.1.0 Returns false if cache key is invalid.
*
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. Not used.
* @return bool True if contents were set, false if key is invalid.
*/
public function set( $key, $data, $group = 'default', $expire = 0 ) {
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( is_object( $data ) ) {
$data = clone $data;
}
$this->cache[ $group ][ $key ] = $data;
return true;
}
/**
* Sets multiple values to the cache in one call.
*
* @since 6.0.0
*
* @param array $data Array of key and value to be set.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool[] Array of return values, grouped by key. Each value is always true.
*/
public function set_multiple( array $data, $group = '', $expire = 0 ) {
$values = array();
foreach ( $data as $key => $value ) {
$values[ $key ] = $this->set( $key, $value, $group, $expire );
}
return $values;
}
/**
* Retrieves the cache contents, if it exists.
*
* The contents will be first attempted to be retrieved by searching by the
* key in the cache group. If the cache is hit (success) then the contents
* are returned.
*
* On failure, the number of cache misses will be incremented.
*
* @since 2.0.0
*
* @param int|string $key The key under which the cache contents are stored.
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
* @param bool $force Optional. Unused. Whether to force an update of the local cache
* from the persistent cache. Default false.
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
* Disambiguates a return of false, a storable value. Default null.
* @return mixed|false The cache contents on success, false on failure to retrieve contents.
*/
public function get( $key, $group = 'default', $force = false, &$found = null ) {
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( $this->_exists( $key, $group ) ) {
$found = true;
$this->cache_hits += 1;
if ( is_object( $this->cache[ $group ][ $key ] ) ) {
return clone $this->cache[ $group ][ $key ];
} else {
return $this->cache[ $group ][ $key ];
}
}
$found = false;
$this->cache_misses += 1;
return false;
}
/**
* Retrieves multiple values from the cache in one call.
*
* @since 5.5.0
*
* @param array $keys Array of keys under which the cache contents are stored.
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
* @param bool $force Optional. Whether to force an update of the local cache
* from the persistent cache. Default false.
* @return array Array of return values, grouped by key. Each value is either
* the cache contents on success, or false on failure.
*/
public function get_multiple( $keys, $group = 'default', $force = false ) {
$values = array();
foreach ( $keys as $key ) {
$values[ $key ] = $this->get( $key, $group, $force );
}
return $values;
}
/**
* Removes the contents of the cache key in the group.
*
* If the cache key does not exist in the group, then nothing will happen.
*
* @since 2.0.0
*
* @param int|string $key What the contents in the cache are called.
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
* @param bool $deprecated Optional. Unused. Default false.
* @return bool True on success, false if the contents were not deleted.
*/
public function delete( $key, $group = 'default', $deprecated = false ) {
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $key, $group ) ) {
return false;
}
unset( $this->cache[ $group ][ $key ] );
return true;
}
/**
* Deletes multiple values from the cache in one call.
*
* @since 6.0.0
*
* @param array $keys Array of keys to be deleted.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @return bool[] Array of return values, grouped by key. Each value is either
* true on success, or false if the contents were not deleted.
*/
public function delete_multiple( array $keys, $group = '' ) {
$values = array();
foreach ( $keys as $key ) {
$values[ $key ] = $this->delete( $key, $group );
}
return $values;
}
/**
* Increments numeric cache item's value.
*
* @since 3.3.0
*
* @param int|string $key The cache key to increment.
* @param int $offset Optional. The amount by which to increment the item's value.
* Default 1.
* @param string $group Optional. The group the key is in. Default 'default'.
* @return int|false The item's new value on success, false on failure.
*/
public function incr( $key, $offset = 1, $group = 'default' ) {
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $key, $group ) ) {
return false;
}
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
$this->cache[ $group ][ $key ] = 0;
}
$offset = (int) $offset;
$this->cache[ $group ][ $key ] += $offset;
if ( $this->cache[ $group ][ $key ] < 0 ) {
$this->cache[ $group ][ $key ] = 0;
}
return $this->cache[ $group ][ $key ];
}
/**
* Decrements numeric cache item's value.
*
* @since 3.3.0
*
* @param int|string $key The cache key to decrement.
* @param int $offset Optional. The amount by which to decrement the item's value.
* Default 1.
* @param string $group Optional. The group the key is in. Default 'default'.
* @return int|false The item's new value on success, false on failure.
*/
public function decr( $key, $offset = 1, $group = 'default' ) {
if ( ! $this->is_valid_key( $key ) ) {
return false;
}
if ( empty( $group ) ) {
$group = 'default';
}
if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
$key = $this->blog_prefix . $key;
}
if ( ! $this->_exists( $key, $group ) ) {
return false;
}
if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
$this->cache[ $group ][ $key ] = 0;
}
$offset = (int) $offset;
$this->cache[ $group ][ $key ] -= $offset;
if ( $this->cache[ $group ][ $key ] < 0 ) {
$this->cache[ $group ][ $key ] = 0;
}
return $this->cache[ $group ][ $key ];
}
/**
* Clears the object cache of all data.
*
* @since 2.0.0
*
* @return true Always returns true.
*/
public function flush() {
$this->cache = array();
return true;
}
/**
* Removes all cache items in a group.
*
* @since 6.1.0
*
* @param string $group Name of group to remove from cache.
* @return true Always returns true.
*/
public function flush_group( $group ) {
unset( $this->cache[ $group ] );
return true;
}
/**
* Sets the list of global cache groups.
*
* @since 3.0.0
*
* @param string|string[] $groups List of groups that are global.
*/
public function add_global_groups( $groups ) {
$groups = (array) $groups;
$groups = array_fill_keys( $groups, true );
$this->global_groups = array_merge( $this->global_groups, $groups );
}
/**
* Switches the internal blog ID.
*
* This changes the blog ID used to create keys in blog specific groups.
*
* @since 3.5.0
*
* @param int $blog_id Blog ID.
*/
public function switch_to_blog( $blog_id ) {
$blog_id = (int) $blog_id;
$this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
}
/**
* Resets cache keys.
*
* @since 3.0.0
*
* @deprecated 3.5.0 Use WP_Object_Cache::switch_to_blog()
* @see switch_to_blog()
*/
public function reset() {
_deprecated_function( __FUNCTION__, '3.5.0', 'WP_Object_Cache::switch_to_blog()' );
// Clear out non-global caches since the blog ID has changed.
foreach ( array_keys( $this->cache ) as $group ) {
if ( ! isset( $this->global_groups[ $group ] ) ) {
unset( $this->cache[ $group ] );
}
}
}
/**
* Echoes the stats of the caching.
*
* Gives the cache hits, and cache misses. Also prints every cached group,
* key and the data.
*
* @since 2.0.0
*/
public function stats() {
echo '<p>';
echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
echo '</p>';
echo '<ul>';
foreach ( $this->cache as $group => $cache ) {
echo '<li><strong>Group:</strong> ' . esc_html( $group ) . ' - ( ' . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
}
echo '</ul>';
}
}
<?php
/**
* Main WordPress API
*
* @package WordPress
*/
// Don't load directly.
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
require ABSPATH . WPINC . '/option.php';
/**
* Converts given MySQL date string into a different format.
*
* - `$format` should be a PHP date format string.
* - 'U' and 'G' formats will return an integer sum of timestamp with timezone offset.
* - `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`).
*
* Historically UTC time could be passed to the function to produce Unix timestamp.
*
* If `$translate` is true then the given date and format string will
* be passed to `wp_date()` for translation.
*
* @since 0.71
*
* @param string $format Format of the date to return.
* @param string $date Date string to convert.
* @param bool $translate Whether the return date should be translated. Default true.
* @return string|int|false Integer if `$format` is 'U' or 'G', string otherwise.
* False on failure.
*/
function mysql2date( $format, $date, $translate = true ) {
if ( empty( $date ) ) {
return false;
}
$timezone = wp_timezone();
$datetime = date_create( $date, $timezone );
if ( false === $datetime ) {
return false;
}
// Returns a sum of timestamp with timezone offset. Ideally should never be used.
if ( 'G' === $format || 'U' === $format ) {
return $datetime->getTimestamp() + $datetime->getOffset();
}
if ( $translate ) {
return wp_date( $format, $datetime->getTimestamp(), $timezone );
}
return $datetime->format( $format );
}
/**
* Retrieves the current time based on specified type.
*
* - The 'mysql' type will return the time in the format for MySQL DATETIME field.
* - The 'timestamp' or 'U' types will return the current timestamp or a sum of timestamp
* and timezone offset, depending on `$gmt`.
* - Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
*
* If `$gmt` is a truthy value then both types will use GMT time, otherwise the
* output is adjusted with the GMT offset for the site.
*
* @since 1.0.0
* @since 5.3.0 Now returns an integer if `$type` is 'U'. Previously a string was returned.
*
* @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U',
* or PHP date format string (e.g. 'Y-m-d').
* @param int|bool $gmt Optional. Whether to use GMT timezone. Default false.
* @return int|string Integer if `$type` is 'timestamp' or 'U', string otherwise.
*/
function current_time( $type, $gmt = 0 ) {
// Don't use non-GMT timestamp, unless you know the difference and really need to.
if ( 'timestamp' === $type || 'U' === $type ) {
return $gmt ? time() : time() + (int) ( (float) get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
}
if ( 'mysql' === $type ) {
$type = 'Y-m-d H:i:s';
}
$timezone = $gmt ? new DateTimeZone( 'UTC' ) : wp_timezone();
$datetime = new DateTime( 'now', $timezone );
return $datetime->format( $type );
}
/**
* Retrieves the current time as an object using the site's timezone.
*
* @since 5.3.0
*
* @return DateTimeImmutable Date and time object.
*/
function current_datetime() {
return new DateTimeImmutable( 'now', wp_timezone() );
}
/**
* Retrieves the timezone of the site as a string.
*
* Uses the `timezone_string` option to get a proper timezone name if available,
* otherwise falls back to a manual UTC ± offset.
*
* Example return values:
*
* - 'Europe/Rome'
* - 'America/North_Dakota/New_Salem'
* - 'UTC'
* - '-06:30'
* - '+00:00'
* - '+08:45'
*
* @since 5.3.0
*
* @return string PHP timezone name or a ±HH:MM offset.
*/
function wp_timezone_string() {
$timezone_string = get_option( 'timezone_string' );
if ( $timezone_string ) {
return $timezone_string;
}
$offset = (float) get_option( 'gmt_offset' );
$hours = (int) $offset;
$minutes = ( $offset - $hours );
$sign = ( $offset < 0 ) ? '-' : '+';
$abs_hour = abs( $hours );
$abs_mins = abs( $minutes * 60 );
$tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
return $tz_offset;
}
/**
* Retrieves the timezone of the site as a `DateTimeZone` object.
*
* Timezone can be based on a PHP timezone string or a ±HH:MM offset.
*
* @since 5.3.0
*
* @return DateTimeZone Timezone object.
*/
function wp_timezone() {
return new DateTimeZone( wp_timezone_string() );
}
/**
* Retrieves the date in localized format, based on a sum of Unix timestamp and
* timezone offset in seconds.
*
* If the locale specifies the locale month and weekday, then the locale will
* take over the format for the date. If it isn't, then the date format string
* will be used instead.
*
* Note that due to the way WP typically generates a sum of timestamp and offset
* with `strtotime()`, it implies offset added at a _current_ time, not at the time
* the timestamp represents. Storing such timestamps or calculating them differently
* will lead to invalid output.
*
* @since 0.71
* @since 5.3.0 Converted into a wrapper for wp_date().
*
* @param string $format Format to display the date.
* @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset
* in seconds. Default false.
* @param bool $gmt Optional. Whether to use GMT timezone. Only applies
* if timestamp is not provided. Default false.
* @return string The date, translated if locale specifies it.
*/
function date_i18n( $format, $timestamp_with_offset = false, $gmt = false ) {
$timestamp = $timestamp_with_offset;
// If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true).
if ( ! is_numeric( $timestamp ) ) {
// phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
$timestamp = current_time( 'timestamp', $gmt );
}
/*
* This is a legacy implementation quirk that the returned timestamp is also with offset.
* Ideally this function should never be used to produce a timestamp.
*/
if ( 'U' === $format ) {
$date = $timestamp;
} elseif ( $gmt && false === $timestamp_with_offset ) { // Current time in UTC.
$date = wp_date( $format, null, new DateTimeZone( 'UTC' ) );
} elseif ( false === $timestamp_with_offset ) { // Current time in site's timezone.
$date = wp_date( $format );
} else {
/*
* Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone.
* This is the best attempt to reverse that operation into a local time to use.
*/
$local_time = gmdate( 'Y-m-d H:i:s', $timestamp );
$timezone = wp_timezone();
$datetime = date_create( $local_time, $timezone );
$date = wp_date( $format, $datetime->getTimestamp(), $timezone );
}
/**
* Filters the date formatted based on the locale.
*
* @since 2.8.0
*
* @param string $date Formatted date string.
* @param string $format Format to display the date.
* @param int $timestamp A sum of Unix timestamp and timezone offset in seconds.
* Might be without offset if input omitted timestamp but requested GMT.
* @param bool $gmt Whether to use GMT timezone. Only applies if timestamp was not provided.
* Default false.
*/
$date = apply_filters( 'date_i18n', $date, $format, $timestamp, $gmt );
return $date;
}
/**
* Retrieves the date, in localized format.
*
* This is a newer function, intended to replace `date_i18n()` without legacy quirks in it.
*
* Note that, unlike `date_i18n()`, this function accepts a true Unix timestamp, not summed
* with timezone offset.
*
* @since 5.3.0
*
* @global WP_Locale $wp_locale WordPress date and time locale object.
*
* @param string $format PHP date format.
* @param int $timestamp Optional. Unix timestamp. Defaults to current time.
* @param DateTimeZone $timezone Optional. Timezone to output result in. Defaults to timezone
* from site settings.
* @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
*/
function wp_date( $format, $timestamp = null, $timezone = null ) {
global $wp_locale;
if ( null === $timestamp ) {
$timestamp = time();
} elseif ( ! is_numeric( $timestamp ) ) {
return false;
}
if ( ! $timezone ) {
$timezone = wp_timezone();
}
$datetime = date_create( '@' . $timestamp );
$datetime->setTimezone( $timezone );
if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) {
$date = $datetime->format( $format );
} else {
// We need to unpack shorthand `r` format because it has parts that might be localized.
$format = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $format );
$new_format = '';
$format_length = strlen( $format );
$month = $wp_locale->get_month( $datetime->format( 'm' ) );
$weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) );
for ( $i = 0; $i < $format_length; $i++ ) {
switch ( $format[ $i ] ) {
case 'D':
$new_format .= addcslashes( $wp_locale->get_weekday_abbrev( $weekday ), '\\A..Za..z' );
break;
case 'F':
$new_format .= addcslashes( $month, '\\A..Za..z' );
break;
case 'l':
$new_format .= addcslashes( $weekday, '\\A..Za..z' );
break;
case 'M':
$new_format .= addcslashes( $wp_locale->get_month_abbrev( $month ), '\\A..Za..z' );
break;
case 'a':
$new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'a' ) ), '\\A..Za..z' );
break;
case 'A':
$new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'A' ) ), '\\A..Za..z' );
break;
case '\\':
$new_format .= $format[ $i ];
// If character follows a slash, we add it without translating.
if ( $i < $format_length ) {
$new_format .= $format[ ++$i ];
}
break;
default:
$new_format .= $format[ $i ];
break;
}
}
$date = $datetime->format( $new_format );
$date = wp_maybe_decline_date( $date, $format );
}
/**
* Filters the date formatted based on the locale.
*
* @since 5.3.0
*
* @param string $date Formatted date string.
* @param string $format Format to display the date.
* @param int $timestamp Unix timestamp.
* @param DateTimeZone $timezone Timezone.
*/
$date = apply_filters( 'wp_date', $date, $format, $timestamp, $timezone );
return $date;
}
/**
* Determines if the date should be declined.
*
* If the locale specifies that month names require a genitive case in certain
* formats (like 'j F Y'), the month name will be replaced with a correct form.
*
* @since 4.4.0
* @since 5.4.0 The `$format` parameter was added.
*
* @global WP_Locale $wp_locale WordPress date and time locale object.
*
* @param string $date Formatted date string.
* @param string $format Optional. Date format to check. Default empty string.
* @return string The date, declined if locale specifies it.
*/
function wp_maybe_decline_date( $date, $format = '' ) {
global $wp_locale;
// i18n functions are not available in SHORTINIT mode.
if ( ! function_exists( '_x' ) ) {
return $date;
}
/*
* translators: If months in your language require a genitive case,
* translate this to 'on'. Do not translate into your own language.
*/
if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
$months = $wp_locale->month;
$months_genitive = $wp_locale->month_genitive;
/*
* Match a format like 'j F Y' or 'j. F' (day of the month, followed by month name)
* and decline the month.
*/
if ( $format ) {
$decline = preg_match( '#[dj]\.? F#', $format );
} else {
// If the format is not passed, try to guess it from the date string.
$decline = preg_match( '#\b\d{1,2}\.? [^\d ]+\b#u', $date );
}
if ( $decline ) {
foreach ( $months as $key => $month ) {
$months[ $key ] = '# ' . preg_quote( $month, '#' ) . '\b#u';
}
foreach ( $months_genitive as $key => $month ) {
$months_genitive[ $key ] = ' ' . $month;
}
$date = preg_replace( $months, $months_genitive, $date );
}
/*
* Match a format like 'F jS' or 'F j' (month name, followed by day with an optional ordinal suffix)
* and change it to declined 'j F'.
*/
if ( $format ) {
$decline = preg_match( '#F [dj]#', $format );
} else {
// If the format is not passed, try to guess it from the date string.
$decline = preg_match( '#\b[^\d ]+ \d{1,2}(st|nd|rd|th)?\b#u', trim( $date ) );
}
if ( $decline ) {
foreach ( $months as $key => $month ) {
$months[ $key ] = '#\b' . preg_quote( $month, '#' ) . ' (\d{1,2})(st|nd|rd|th)?([-–]\d{1,2})?(st|nd|rd|th)?\b#u';
}
foreach ( $months_genitive as $key => $month ) {
$months_genitive[ $key ] = '$1$3 ' . $month;
}
$date = preg_replace( $months, $months_genitive, $date );
}
}
// Used for locale-specific rules.
$locale = get_locale();
if ( 'ca' === $locale ) {
// " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
$date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
}
return $date;
}
/**
* Converts float number to format based on the locale.
*
* @since 2.3.0
*
* @global WP_Locale $wp_locale WordPress date and time locale object.
*
* @param float $number The number to convert based on locale.
* @param int $decimals Optional. Precision of the number of decimal places. Default 0.
* @return string Converted number in string format.
*/
function number_format_i18n( $number, $decimals = 0 ) {
global $wp_locale;
if ( isset( $wp_locale ) ) {
$formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
} else {
$formatted = number_format( $number, absint( $decimals ) );
}
/**
* Filters the number formatted based on the locale.
*
* @since 2.8.0
* @since 4.9.0 The `$number` and `$decimals` parameters were added.
*
* @param string $formatted Converted number in string format.
* @param float $number The number to convert based on locale.
* @param int $decimals Precision of the number of decimal places.
*/
return apply_filters( 'number_format_i18n', $formatted, $number, $decimals );
}
/**
* Converts a number of bytes to the largest unit the bytes will fit into.
*
* It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
* number of bytes to human readable number by taking the number of that unit
* that the bytes will go into it. Supports YB value.
*
* Please note that integers in PHP are limited to 32 bits, unless they are on
* 64 bit architecture, then they have 64 bit size. If you need to place the
* larger size then what PHP integer type will hold, then use a string. It will
* be converted to a double, which should always have 64 bit length.
*
* Technically the correct unit names for powers of 1024 are KiB, MiB etc.
*
* @since 2.3.0
* @since 6.0.0 Support for PB, EB, ZB, and YB was added.
*
* @param int|string $bytes Number of bytes. Note max integer size for integers.
* @param int $decimals Optional. Precision of number of decimal places. Default 0.
* @return string|false Number string on success, false on failure.
*/
function size_format( $bytes, $decimals = 0 ) {
$quant = array(
/* translators: Unit symbol for yottabyte. */
_x( 'YB', 'unit symbol' ) => YB_IN_BYTES,
/* translators: Unit symbol for zettabyte. */
_x( 'ZB', 'unit symbol' ) => ZB_IN_BYTES,
/* translators: Unit symbol for exabyte. */
_x( 'EB', 'unit symbol' ) => EB_IN_BYTES,
/* translators: Unit symbol for petabyte. */
_x( 'PB', 'unit symbol' ) => PB_IN_BYTES,
/* translators: Unit symbol for terabyte. */
_x( 'TB', 'unit symbol' ) => TB_IN_BYTES,
/* translators: Unit symbol for gigabyte. */
_x( 'GB', 'unit symbol' ) => GB_IN_BYTES,
/* translators: Unit symbol for megabyte. */
_x( 'MB', 'unit symbol' ) => MB_IN_BYTES,
/* translators: Unit symbol for kilobyte. */
_x( 'KB', 'unit symbol' ) => KB_IN_BYTES,
/* translators: Unit symbol for byte. */
_x( 'B', 'unit symbol' ) => 1,
);
if ( 0 === $bytes ) {
/* translators: Unit symbol for byte. */
return number_format_i18n( 0, $decimals ) . ' ' . _x( 'B', 'unit symbol' );
}
foreach ( $quant as $unit => $mag ) {
if ( (float) $bytes >= $mag ) {
return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
}
}
return false;
}
/**
* Converts a duration to human readable format.
*
* @since 5.1.0
*
* @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
* with a possible prepended negative sign (-).
* @return string|false A human readable duration string, false on failure.
*/
function human_readable_duration( $duration = '' ) {
if ( ( empty( $duration ) || ! is_string( $duration ) ) ) {
return false;
}
$duration = trim( $duration );
// Remove prepended negative sign.
if ( str_starts_with( $duration, '-' ) ) {
$duration = substr( $duration, 1 );
}
// Extract duration parts.
$duration_parts = array_reverse( explode( ':', $duration ) );
$duration_count = count( $duration_parts );
$hour = null;
$minute = null;
$second = null;
if ( 3 === $duration_count ) {
// Validate HH:ii:ss duration format.
if ( ! ( (bool) preg_match( '/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
return false;
}
// Three parts: hours, minutes & seconds.
list( $second, $minute, $hour ) = $duration_parts;
} elseif ( 2 === $duration_count ) {
// Validate ii:ss duration format.
if ( ! ( (bool) preg_match( '/^([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
return false;
}
// Two parts: minutes & seconds.
list( $second, $minute ) = $duration_parts;
} else {
return false;
}
$human_readable_duration = array();
// Add the hour part to the string.
if ( is_numeric( $hour ) ) {
/* translators: %s: Time duration in hour or hours. */
$human_readable_duration[] = sprintf( _n( '%s hour', '%s hours', $hour ), (int) $hour );
}
// Add the minute part to the string.
if ( is_numeric( $minute ) ) {
/* translators: %s: Time duration in minute or minutes. */
$human_readable_duration[] = sprintf( _n( '%s minute', '%s minutes', $minute ), (int) $minute );
}
// Add the second part to the string.
if ( is_numeric( $second ) ) {
/* translators: %s: Time duration in second or seconds. */
$human_readable_duration[] = sprintf( _n( '%s second', '%s seconds', $second ), (int) $second );
}
return implode( ', ', $human_readable_duration );
}
/**
* Gets the week start and end from the datetime or date string from MySQL.
*
* @since 0.71
*
* @param string $mysqlstring Date or datetime field type from MySQL.
* @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
* @return int[] {
* Week start and end dates as Unix timestamps.
*
* @type int $start The week start date as a Unix timestamp.
* @type int $end The week end date as a Unix timestamp.
* }
*/
function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
// MySQL string year.
$my = substr( $mysqlstring, 0, 4 );
// MySQL string month.
$mm = substr( $mysqlstring, 8, 2 );
// MySQL string day.
$md = substr( $mysqlstring, 5, 2 );
// The timestamp for MySQL string day.
$day = mktime( 0, 0, 0, $md, $mm, $my );
// The day of the week from the timestamp.
$weekday = (int) gmdate( 'w', $day );
if ( ! is_numeric( $start_of_week ) ) {
$start_of_week = (int) get_option( 'start_of_week' );
}
if ( $weekday < $start_of_week ) {
$weekday += 7;
}
// The most recent week start day on or before $day.
$start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
// $start + 1 week - 1 second.
$end = $start + WEEK_IN_SECONDS - 1;
return compact( 'start', 'end' );
}
/**
* Serializes data, if needed.
*
* @since 2.0.5
*
* @param string|array|object $data Data that might be serialized.
* @return mixed A scalar data.
*/
function maybe_serialize( $data ) {
if ( is_array( $data ) || is_object( $data ) ) {
return serialize( $data );
}
/*
* Double serialization is required for backward compatibility.
* See https://core.trac.wordpress.org/ticket/12930
* Also the world will end. See WP 3.6.1.
*/
if ( is_serialized( $data, false ) ) {
return serialize( $data );
}
return $data;
}
/**
* Unserializes data only if it was serialized.
*
* @since 2.0.0
*
* @param string $data Data that might be unserialized.
* @return mixed Unserialized data can be any type.
*/
function maybe_unserialize( $data ) {
if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
return @unserialize( trim( $data ) );
}
return $data;
}
/**
* Checks value to find if it was serialized.
*
* If $data is not a string, then returned value will always be false.
* Serialized data is always a string.
*
* @since 2.0.5
* @since 6.1.0 Added Enum support.
*
* @param string $data Value to check to see if was serialized.
* @param bool $strict Optional. Whether to be strict about the end of the string. Default true.
* @return bool False if not serialized and true if it was.
*/
function is_serialized( $data, $strict = true ) {
// If it isn't a string, it isn't serialized.
if ( ! is_string( $data ) ) {
return false;
}
$data = trim( $data );
if ( 'N;' === $data ) {
return true;
}
if ( strlen( $data ) < 4 ) {
return false;
}
if ( ':' !== $data[1] ) {
return false;
}
if ( $strict ) {
$lastc = substr( $data, -1 );
if ( ';' !== $lastc && '}' !== $lastc ) {
return false;
}
} else {
$semicolon = strpos( $data, ';' );
$brace = strpos( $data, '}' );
// Either ; or } must exist.
if ( false === $semicolon && false === $brace ) {
return false;
}
// But neither must be in the first X characters.
if ( false !== $semicolon && $semicolon < 3 ) {
return false;
}
if ( false !== $brace && $brace < 4 ) {
return false;
}
}
$token = $data[0];
switch ( $token ) {
case 's':
if ( $strict ) {
if ( '"' !== substr( $data, -2, 1 ) ) {
return false;
}
} elseif ( ! str_contains( $data, '"' ) ) {
return false;
}
// Or else fall through.
case 'a':
case 'O':
case 'E':
return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
case 'b':
case 'i':
case 'd':
$end = $strict ? '$' : '';
return (bool) preg_match( "/^{$token}:[0-9.E+-]+;$end/", $data );
}
return false;
}
/**
* Checks whether serialized data is of string type.
*
* @since 2.0.5
*
* @param string $data Serialized data.
* @return bool False if not a serialized string, true if it is.
*/
function is_serialized_string( $data ) {
// if it isn't a string, it isn't a serialized string.
if ( ! is_string( $data ) ) {
return false;
}
$data = trim( $data );
if ( strlen( $data ) < 4 ) {
return false;
} elseif ( ':' !== $data[1] ) {
return false;
} elseif ( ! str_ends_with( $data, ';' ) ) {
return false;
} elseif ( 's' !== $data[0] ) {
return false;
} elseif ( '"' !== substr( $data, -2, 1 ) ) {
return false;
} else {
return true;
}
}
/**
* Retrieves post title from XMLRPC XML.
*
* If the title element is not part of the XML, then the default post title from
* the $post_default_title will be used instead.
*
* @since 0.71
*
* @global string $post_default_title Default XML-RPC post title.
*
* @param string $content XMLRPC XML Request content
* @return string Post title
*/
function xmlrpc_getposttitle( $content ) {
global $post_default_title;
if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
$post_title = $matchtitle[1];
} else {
$post_title = $post_default_title;
}
return $post_title;
}
/**
* Retrieves the post category or categories from XMLRPC XML.
*
* If the category element is not found, then the default post category will be
* used. The return type then would be what $post_default_category. If the
* category is found, then it will always be an array.
*
* @since 0.71
*
* @global string $post_default_category Default XML-RPC post category.
*
* @param string $content XMLRPC XML Request content
* @return string|array List of categories or category name.
*/
function xmlrpc_getpostcategory( $content ) {
global $post_default_category;
if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
$post_category = trim( $matchcat[1], ',' );
$post_category = explode( ',', $post_category );
} else {
$post_category = $post_default_category;
}
return $post_category;
}
/**
* XMLRPC XML content without title and category elements.
*
* @since 0.71
*
* @param string $content XML-RPC XML Request content.
* @return string XMLRPC XML Request content without title and category elements.
*/
function xmlrpc_removepostdata( $content ) {
$content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
$content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
$content = trim( $content );
return $content;
}
/**
* Uses RegEx to extract URLs from arbitrary content.
*
* @since 3.7.0
* @since 6.0.0 Fixes support for HTML entities (Trac 30580).
*
* @param string $content Content to extract URLs from.
* @return string[] Array of URLs found in passed string.
*/
function wp_extract_urls( $content ) {
preg_match_all(
"#([\"']?)("
. '(?:([\w-]+:)?//?)'
. '[^\s()<>]+'
. '[.]'
. '(?:'
. '\([\w\d]+\)|'
. '(?:'
. "[^`!()\[\]{}:'\".,<>«»“”‘’\s]|"
. '(?:[:]\d+)?/?'
. ')+'
. ')'
. ")\\1#",
$content,
$post_links
);
$post_links = array_unique(
array_map(
static function ( $link ) {
// Decode to replace valid entities, like &.
$link = html_entity_decode( $link );
// Maintain backward compatibility by removing extraneous semi-colons (`;`).
return str_replace( ';', '', $link );
},
$post_links[2]
)
);
return array_values( $post_links );
}
/**
* Checks content for video and audio links to add as enclosures.
*
* Will not add enclosures that have already been added and will
* remove enclosures that are no longer in the post. This is called as
* pingbacks and trackbacks.
*
* @since 1.5.0
* @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was
* updated to accept a post ID or a WP_Post object.
* @since 5.6.0 The `$content` parameter is no longer optional, but passing `null` to skip it
* is still supported.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string|null $content Post content. If `null`, the `post_content` field from `$post` is used.
* @param int|WP_Post $post Post ID or post object.
* @return void|false Void on success, false if the post is not found.
*/
function do_enclose( $content, $post ) {
global $wpdb;
// @todo Tidy this code and make the debug code optional.
require_once ABSPATH . WPINC . '/class-IXR.php';
$post = get_post( $post );
if ( ! $post ) {
return false;
}
if ( null === $content ) {
$content = $post->post_content;
}
$post_links = array();
$pung = get_enclosed( $post->ID );
$post_links_temp = wp_extract_urls( $content );
foreach ( $pung as $link_test ) {
// Link is no longer in post.
if ( ! in_array( $link_test, $post_links_temp, true ) ) {
$mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $link_test ) . '%' ) );
foreach ( $mids as $mid ) {
delete_metadata_by_mid( 'post', $mid );
}
}
}
foreach ( (array) $post_links_temp as $link_test ) {
// If we haven't pung it already.
if ( ! in_array( $link_test, $pung, true ) ) {
$test = parse_url( $link_test );
if ( false === $test ) {
continue;
}
if ( isset( $test['query'] ) ) {
$post_links[] = $link_test;
} elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) {
$post_links[] = $link_test;
}
}
}
/**
* Filters the list of enclosure links before querying the database.
*
* Allows for the addition and/or removal of potential enclosures to save
* to postmeta before checking the database for existing enclosures.
*
* @since 4.4.0
*
* @param string[] $post_links An array of enclosure links.
* @param int $post_id Post ID.
*/
$post_links = apply_filters( 'enclosure_links', $post_links, $post->ID );
foreach ( (array) $post_links as $url ) {
$url = strip_fragment_from_url( $url );
if ( '' !== $url && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
$headers = wp_get_http_headers( $url );
if ( $headers ) {
$len = isset( $headers['Content-Length'] ) ? (int) $headers['Content-Length'] : 0;
$type = isset( $headers['Content-Type'] ) ? $headers['Content-Type'] : '';
$allowed_types = array( 'video', 'audio' );
// Check to see if we can figure out the mime type from the extension.
$url_parts = parse_url( $url );
if ( false !== $url_parts && ! empty( $url_parts['path'] ) ) {
$extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
if ( ! empty( $extension ) ) {
foreach ( wp_get_mime_types() as $exts => $mime ) {
if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
$type = $mime;
break;
}
}
}
}
if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types, true ) ) {
add_post_meta( $post->ID, 'enclosure', "$url\n$len\n$mime\n" );
}
}
}
}
}
/**
* Retrieves HTTP Headers from URL.
*
* @since 1.5.1
*
* @param string $url URL to retrieve HTTP headers from.
* @param bool $deprecated Not Used.
* @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary|false Headers on success, false on failure.
*/
function wp_get_http_headers( $url, $deprecated = false ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.7.0' );
}
$response = wp_safe_remote_head( $url );
if ( is_wp_error( $response ) ) {
return false;
}
return wp_remote_retrieve_headers( $response );
}
/**
* Determines whether the publish date of the current post in the loop is different
* from the publish date of the previous post in the loop.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 0.71
*
* @global string $currentday The day of the current post in the loop.
* @global string $previousday The day of the previous post in the loop.
*
* @return int 1 when new day, 0 if not a new day.
*/
function is_new_day() {
global $currentday, $previousday;
if ( $currentday !== $previousday ) {
return 1;
} else {
return 0;
}
}
/**
* Builds URL query based on an associative and, or indexed array.
*
* This is a convenient function for easily building url queries. It sets the
* separator to '&' and uses _http_build_query() function.
*
* @since 2.3.0
*
* @see _http_build_query() Used to build the query
* @link https://www.php.net/manual/en/function.http-build-query.php for more on what
* http_build_query() does.
*
* @param array $data URL-encode key/value pairs.
* @return string URL-encoded string.
*/
function build_query( $data ) {
return _http_build_query( $data, null, '&', '', false );
}
/**
* From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
*
* @since 3.2.0
* @access private
*
* @see https://www.php.net/manual/en/function.http-build-query.php
*
* @param array|object $data An array or object of data. Converted to array.
* @param string $prefix Optional. Numeric index. If set, start parameter numbering with it.
* Default null.
* @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'.
* Default null.
* @param string $key Optional. Used to prefix key name. Default empty string.
* @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true.
* @return string The query string.
*/
function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
$ret = array();
foreach ( (array) $data as $k => $v ) {
if ( $urlencode ) {
$k = urlencode( $k );
}
if ( is_int( $k ) && null !== $prefix ) {
$k = $prefix . $k;
}
if ( ! empty( $key ) ) {
$k = $key . '%5B' . $k . '%5D';
}
if ( null === $v ) {
continue;
} elseif ( false === $v ) {
$v = '0';
}
if ( is_array( $v ) || is_object( $v ) ) {
array_push( $ret, _http_build_query( $v, '', $sep, $k, $urlencode ) );
} elseif ( $urlencode ) {
array_push( $ret, $k . '=' . urlencode( $v ) );
} else {
array_push( $ret, $k . '=' . $v );
}
}
if ( null === $sep ) {
$sep = ini_get( 'arg_separator.output' );
}
return implode( $sep, $ret );
}
/**
* Retrieves a modified URL query string.
*
* You can rebuild the URL and append query variables to the URL query by using this function.
* There are two ways to use this function; either a single key and value, or an associative array.
*
* Using a single key and value:
*
* add_query_arg( 'key', 'value', 'http://example.com' );
*
* Using an associative array:
*
* add_query_arg( array(
* 'key1' => 'value1',
* 'key2' => 'value2',
* ), 'http://example.com' );
*
* Omitting the URL from either use results in the current URL being used
* (the value of `$_SERVER['REQUEST_URI']`).
*
* Values are expected to be encoded appropriately with urlencode() or rawurlencode().
*
* Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
*
* Important: The return value of add_query_arg() is not escaped by default. Output should be
* late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
* (XSS) attacks.
*
* @since 1.5.0
* @since 5.3.0 Formalized the existing and already documented parameters
* by adding `...$args` to the function signature.
*
* @param string|array $key Either a query variable key, or an associative array of query variables.
* @param string $value Optional. Either a query variable value, or a URL to act upon.
* @param string $url Optional. A URL to act upon.
* @return string New URL query string (unescaped).
*/
function add_query_arg( ...$args ) {
if ( is_array( $args[0] ) ) {
if ( count( $args ) < 2 || false === $args[1] ) {
$uri = $_SERVER['REQUEST_URI'];
} else {
$uri = $args[1];
}
} else {
if ( count( $args ) < 3 || false === $args[2] ) {
$uri = $_SERVER['REQUEST_URI'];
} else {
$uri = $args[2];
}
}
$frag = strstr( $uri, '#' );
if ( $frag ) {
$uri = substr( $uri, 0, -strlen( $frag ) );
} else {
$frag = '';
}
if ( 0 === stripos( $uri, 'http://' ) ) {
$protocol = 'http://';
$uri = substr( $uri, 7 );
} elseif ( 0 === stripos( $uri, 'https://' ) ) {
$protocol = 'https://';
$uri = substr( $uri, 8 );
} else {
$protocol = '';
}
if ( str_contains( $uri, '?' ) ) {
list( $base, $query ) = explode( '?', $uri, 2 );
$base .= '?';
} elseif ( $protocol || ! str_contains( $uri, '=' ) ) {
$base = $uri . '?';
$query = '';
} else {
$base = '';
$query = $uri;
}
wp_parse_str( $query, $qs );
$qs = urlencode_deep( $qs ); // This re-URL-encodes things that were already in the query string.
if ( is_array( $args[0] ) ) {
foreach ( $args[0] as $k => $v ) {
$qs[ $k ] = $v;
}
} else {
$qs[ $args[0] ] = $args[1];
}
foreach ( $qs as $k => $v ) {
if ( false === $v ) {
unset( $qs[ $k ] );
}
}
$ret = build_query( $qs );
$ret = trim( $ret, '?' );
$ret = preg_replace( '#=(&|$)#', '$1', $ret );
$ret = $protocol . $base . $ret . $frag;
$ret = rtrim( $ret, '?' );
$ret = str_replace( '?#', '#', $ret );
return $ret;
}
/**
* Removes an item or items from a query string.
*
* Important: The return value of remove_query_arg() is not escaped by default. Output should be
* late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
* (XSS) attacks.
*
* @since 1.5.0
*
* @param string|string[] $key Query key or keys to remove.
* @param false|string $query Optional. When false uses the current URL. Default false.
* @return string New URL query string.
*/
function remove_query_arg( $key, $query = false ) {
if ( is_array( $key ) ) { // Removing multiple keys.
foreach ( $key as $k ) {
$query = add_query_arg( $k, false, $query );
}
return $query;
}
return add_query_arg( $key, false, $query );
}
/**
* Returns an array of single-use query variable names that can be removed from a URL.
*
* @since 4.4.0
*
* @return string[] An array of query variable names to remove from the URL.
*/
function wp_removable_query_args() {
$removable_query_args = array(
'activate',
'activated',
'admin_email_remind_later',
'approved',
'core-major-auto-updates-saved',
'deactivate',
'delete_count',
'deleted',
'disabled',
'doing_wp_cron',
'enabled',
'error',
'hotkeys_highlight_first',
'hotkeys_highlight_last',
'ids',
'locked',
'message',
'same',
'saved',
'settings-updated',
'skipped',
'spammed',
'trashed',
'unspammed',
'untrashed',
'update',
'updated',
'wp-post-new-reload',
);
/**
* Filters the list of query variable names to remove.
*
* @since 4.2.0
*
* @param string[] $removable_query_args An array of query variable names to remove from a URL.
*/
return apply_filters( 'removable_query_args', $removable_query_args );
}
/**
* Walks the array while sanitizing the contents.
*
* @since 0.71
* @since 5.5.0 Non-string values are left untouched.
*
* @param array $input_array Array to walk while sanitizing contents.
* @return array Sanitized $input_array.
*/
function add_magic_quotes( $input_array ) {
foreach ( (array) $input_array as $k => $v ) {
if ( is_array( $v ) ) {
$input_array[ $k ] = add_magic_quotes( $v );
} elseif ( is_string( $v ) ) {
$input_array[ $k ] = addslashes( $v );
}
}
return $input_array;
}
/**
* HTTP request for URI to retrieve content.
*
* @since 1.5.1
*
* @see wp_safe_remote_get()
*
* @param string $uri URI/URL of web page to retrieve.
* @return string|false HTTP content. False on failure.
*/
function wp_remote_fopen( $uri ) {
$parsed_url = parse_url( $uri );
if ( ! $parsed_url || ! is_array( $parsed_url ) ) {
return false;
}
$options = array();
$options['timeout'] = 10;
$response = wp_safe_remote_get( $uri, $options );
if ( is_wp_error( $response ) ) {
return false;
}
return wp_remote_retrieve_body( $response );
}
/**
* Sets up the WordPress query.
*
* @since 2.0.0
*
* @global WP $wp Current WordPress environment instance.
* @global WP_Query $wp_query WordPress Query object.
* @global WP_Query $wp_the_query Copy of the WordPress Query object.
*
* @param string|array $query_vars Default WP_Query arguments.
*/
function wp( $query_vars = '' ) {
global $wp, $wp_query, $wp_the_query;
$wp->main( $query_vars );
if ( ! isset( $wp_the_query ) ) {
$wp_the_query = $wp_query;
}
}
/**
* Retrieves the description for the HTTP status.
*
* @since 2.3.0
* @since 3.9.0 Added status codes 418, 428, 429, 431, and 511.
* @since 4.5.0 Added status codes 308, 421, and 451.
* @since 5.1.0 Added status code 103.
* @since 6.6.0 Added status code 425.
*
* @global array $wp_header_to_desc
*
* @param int $code HTTP status code.
* @return string Status description if found, an empty string otherwise.
*/
function get_status_header_desc( $code ) {
global $wp_header_to_desc;
$code = absint( $code );
if ( ! isset( $wp_header_to_desc ) ) {
$wp_header_to_desc = array(
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
103 => 'Early Hints',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
226 => 'IM Used',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
306 => 'Reserved',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot',
421 => 'Misdirected Request',
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
425 => 'Too Early',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
451 => 'Unavailable For Legal Reasons',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage',
510 => 'Not Extended',
511 => 'Network Authentication Required',
);
}
if ( isset( $wp_header_to_desc[ $code ] ) ) {
return $wp_header_to_desc[ $code ];
} else {
return '';
}
}
/**
* Sets HTTP status header.
*
* @since 2.0.0
* @since 4.4.0 Added the `$description` parameter.
*
* @see get_status_header_desc()
*
* @param int $code HTTP status code.
* @param string $description Optional. A custom description for the HTTP status.
* Defaults to the result of get_status_header_desc() for the given code.
*/
function status_header( $code, $description = '' ) {
if ( ! $description ) {
$description = get_status_header_desc( $code );
}
if ( empty( $description ) ) {
return;
}
$protocol = wp_get_server_protocol();
$status_header = "$protocol $code $description";
if ( function_exists( 'apply_filters' ) ) {
/**
* Filters an HTTP status header.
*
* @since 2.2.0
*
* @param string $status_header HTTP status header.
* @param int $code HTTP status code.
* @param string $description Description for the status code.
* @param string $protocol Server protocol.
*/
$status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
}
if ( ! headers_sent() ) {
header( $status_header, true, $code );
}
}
/**
* Gets the HTTP header information to prevent caching.
*
* The several different headers cover the different ways cache prevention
* is handled by different browsers or intermediate caches such as proxy servers.
*
* @since 2.8.0
* @since 6.3.0 The `Cache-Control` header for logged in users now includes the
* `no-store` and `private` directives.
* @since 6.8.0 The `Cache-Control` header now includes the `no-store` and `private`
* directives regardless of whether a user is logged in.
*
* @return array The associative array of header names and field values.
*/
function wp_get_nocache_headers() {
$cache_control = 'no-cache, must-revalidate, max-age=0, no-store, private';
$headers = array(
'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
'Cache-Control' => $cache_control,
);
if ( function_exists( 'apply_filters' ) ) {
/**
* Filters the cache-controlling HTTP headers that are used to prevent caching.
*
* @since 2.8.0
*
* @see wp_get_nocache_headers()
*
* @param array $headers Header names and field values.
*/
$headers = (array) apply_filters( 'nocache_headers', $headers );
}
$headers['Last-Modified'] = false;
return $headers;
}
/**
* Sets the HTTP headers to prevent caching for the different browsers.
*
* Different browsers support different nocache headers, so several
* headers must be sent so that all of them get the point that no
* caching should occur.
*
* @since 2.0.0
*
* @see wp_get_nocache_headers()
*/
function nocache_headers() {
if ( headers_sent() ) {
return;
}
$headers = wp_get_nocache_headers();
unset( $headers['Last-Modified'] );
header_remove( 'Last-Modified' );
foreach ( $headers as $name => $field_value ) {
header( "{$name}: {$field_value}" );
}
}
/**
* Sets the HTTP headers for caching for 10 days with JavaScript content type.
*
* @since 2.1.0
*/
function cache_javascript_headers() {
$expires_offset = 10 * DAY_IN_SECONDS;
header( 'Content-Type: text/javascript; charset=' . get_bloginfo( 'charset' ) );
header( 'Vary: Accept-Encoding' ); // Handle proxies.
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expires_offset ) . ' GMT' );
}
/**
* Retrieves the number of database queries during the WordPress execution.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return int Number of database queries.
*/
function get_num_queries() {
global $wpdb;
return $wpdb->num_queries;
}
/**
* Determines whether input is yes or no.
*
* Must be 'y' to be true.
*
* @since 1.0.0
*
* @param string $yn Character string containing either 'y' (yes) or 'n' (no).
* @return bool True if 'y', false on anything else.
*/
function bool_from_yn( $yn ) {
return ( 'y' === strtolower( $yn ) );
}
/**
* Loads the feed template from the use of an action hook.
*
* If the feed action does not have a hook, then the function will die with a
* message telling the visitor that the feed is not valid.
*
* It is better to only have one hook for each feed.
*
* @since 2.1.0
*
* @global WP_Query $wp_query WordPress Query object.
*/
function do_feed() {
global $wp_query;
$feed = get_query_var( 'feed' );
// Remove the pad, if present.
$feed = preg_replace( '/^_+/', '', $feed );
if ( '' === $feed || 'feed' === $feed ) {
$feed = get_default_feed();
}
if ( ! has_action( "do_feed_{$feed}" ) ) {
wp_die( __( '<strong>Error:</strong> This is not a valid feed template.' ), '', array( 'response' => 404 ) );
}
/**
* Fires once the given feed is loaded.
*
* The dynamic portion of the hook name, `$feed`, refers to the feed template name.
*
* Possible hook names include:
*
* - `do_feed_atom`
* - `do_feed_rdf`
* - `do_feed_rss`
* - `do_feed_rss2`
*
* @since 2.1.0
* @since 4.4.0 The `$feed` parameter was added.
*
* @param bool $is_comment_feed Whether the feed is a comment feed.
* @param string $feed The feed name.
*/
do_action( "do_feed_{$feed}", $wp_query->is_comment_feed, $feed );
}
/**
* Loads the RDF RSS 0.91 Feed template.
*
* @since 2.1.0
*
* @see load_template()
*/
function do_feed_rdf() {
load_template( ABSPATH . WPINC . '/feed-rdf.php' );
}
/**
* Loads the RSS 1.0 Feed Template.
*
* @since 2.1.0
*
* @see load_template()
*/
function do_feed_rss() {
load_template( ABSPATH . WPINC . '/feed-rss.php' );
}
/**
* Loads either the RSS2 comment feed or the RSS2 posts feed.
*
* @since 2.1.0
*
* @see load_template()
*
* @param bool $for_comments True for the comment feed, false for normal feed.
*/
function do_feed_rss2( $for_comments ) {
if ( $for_comments ) {
load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
} else {
load_template( ABSPATH . WPINC . '/feed-rss2.php' );
}
}
/**
* Loads either Atom comment feed or Atom posts feed.
*
* @since 2.1.0
*
* @see load_template()
*
* @param bool $for_comments True for the comment feed, false for normal feed.
*/
function do_feed_atom( $for_comments ) {
if ( $for_comments ) {
load_template( ABSPATH . WPINC . '/feed-atom-comments.php' );
} else {
load_template( ABSPATH . WPINC . '/feed-atom.php' );
}
}
/**
* Displays the default robots.txt file content.
*
* @since 2.1.0
* @since 5.3.0 Remove the "Disallow: /" output if search engine visibility is
* discouraged in favor of robots meta HTML tag via wp_robots_no_robots()
* filter callback.
*/
function do_robots() {
header( 'Content-Type: text/plain; charset=utf-8' );
/**
* Fires when displaying the robots.txt file.
*
* @since 2.1.0
*/
do_action( 'do_robotstxt' );
$output = "User-agent: *\n";
$public = (bool) get_option( 'blog_public' );
$site_url = parse_url( site_url() );
$path = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : '';
$output .= "Disallow: $path/wp-admin/\n";
$output .= "Allow: $path/wp-admin/admin-ajax.php\n";
/**
* Filters the robots.txt output.
*
* @since 3.0.0
*
* @param string $output The robots.txt output.
* @param bool $public Whether the site is considered "public".
*/
echo apply_filters( 'robots_txt', $output, $public );
}
/**
* Displays the favicon.ico file content.
*
* @since 5.4.0
*/
function do_favicon() {
/**
* Fires when serving the favicon.ico file.
*
* @since 5.4.0
*/
do_action( 'do_faviconico' );
wp_redirect( get_site_icon_url( 32, includes_url( 'images/w-logo-blue-white-bg.png' ) ) );
exit;
}
/**
* Determines whether WordPress is already installed.
*
* The cache will be checked first. If you have a cache plugin, which saves
* the cache values, then this will work. If you use the default WordPress
* cache, and the database goes away, then you might have problems.
*
* Checks for the 'siteurl' option for whether WordPress is installed.
*
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
*
* @since 2.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return bool Whether the site is already installed.
*/
function is_blog_installed() {
global $wpdb;
/*
* Check cache first. If options table goes away and we have true
* cached, oh well.
*/
if ( wp_cache_get( 'is_blog_installed' ) ) {
return true;
}
$suppress = $wpdb->suppress_errors();
if ( ! wp_installing() ) {
$alloptions = wp_load_alloptions();
}
// If siteurl is not set to autoload, check it specifically.
if ( ! isset( $alloptions['siteurl'] ) ) {
$installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
} else {
$installed = $alloptions['siteurl'];
}
$wpdb->suppress_errors( $suppress );
$installed = ! empty( $installed );
wp_cache_set( 'is_blog_installed', $installed );
if ( $installed ) {
return true;
}
// If visiting repair.php, return true and let it take over.
if ( defined( 'WP_REPAIRING' ) ) {
return true;
}
$suppress = $wpdb->suppress_errors();
/*
* Loop over the WP tables. If none exist, then scratch installation is allowed.
* If one or more exist, suggest table repair since we got here because the
* options table could not be accessed.
*/
$wp_tables = $wpdb->tables();
foreach ( $wp_tables as $table ) {
// The existence of custom user tables shouldn't suggest an unwise state or prevent a clean installation.
if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE === $table ) {
continue;
}
if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE === $table ) {
continue;
}
$described_table = $wpdb->get_results( "DESCRIBE $table;" );
if (
( ! $described_table && empty( $wpdb->last_error ) ) ||
( is_array( $described_table ) && 0 === count( $described_table ) )
) {
continue;
}
// One or more tables exist. This is not good.
wp_load_translations_early();
// Die with a DB error.
$wpdb->error = sprintf(
/* translators: %s: Database repair URL. */
__( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ),
'maint/repair.php?referrer=is_blog_installed'
);
dead_db();
}
$wpdb->suppress_errors( $suppress );
wp_cache_set( 'is_blog_installed', false );
return false;
}
/**
* Retrieves URL with nonce added to URL query.
*
* @since 2.0.4
*
* @param string $actionurl URL to add nonce action.
* @param int|string $action Optional. Nonce action name. Default -1.
* @param string $name Optional. Nonce name. Default '_wpnonce'.
* @return string Escaped URL with nonce action added.
*/
function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
$actionurl = str_replace( '&', '&', $actionurl );
return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
}
/**
* Retrieves or display nonce hidden field for forms.
*
* The nonce field is used to validate that the contents of the form came from
* the location on the current site and not somewhere else. The nonce does not
* offer absolute protection, but should protect against most cases. It is very
* important to use nonce field in forms.
*
* The $action and $name are optional, but if you want to have better security,
* it is strongly suggested to set those two parameters. It is easier to just
* call the function without any parameters, because validation of the nonce
* doesn't require any parameters, but since crackers know what the default is
* it won't be difficult for them to find a way around your nonce and cause
* damage.
*
* The input name will be whatever $name value you gave. The input value will be
* the nonce creation value.
*
* @since 2.0.4
*
* @param int|string $action Optional. Action name. Default -1.
* @param string $name Optional. Nonce name. Default '_wpnonce'.
* @param bool $referer Optional. Whether to set the referer field for validation. Default true.
* @param bool $display Optional. Whether to display or return hidden form field. Default true.
* @return string Nonce field HTML markup.
*/
function wp_nonce_field( $action = -1, $name = '_wpnonce', $referer = true, $display = true ) {
$name = esc_attr( $name );
$nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
if ( $referer ) {
$nonce_field .= wp_referer_field( false );
}
if ( $display ) {
echo $nonce_field;
}
return $nonce_field;
}
/**
* Retrieves or displays referer hidden field for forms.
*
* The referer link is the current Request URI from the server super global. The
* input name is '_wp_http_referer', in case you wanted to check manually.
*
* @since 2.0.4
*
* @param bool $display Optional. Whether to echo or return the referer field. Default true.
* @return string Referer field HTML markup.
*/
function wp_referer_field( $display = true ) {
$request_url = remove_query_arg( '_wp_http_referer' );
$referer_field = '<input type="hidden" name="_wp_http_referer" value="' . esc_url( $request_url ) . '" />';
if ( $display ) {
echo $referer_field;
}
return $referer_field;
}
/**
* Retrieves or displays original referer hidden field for forms.
*
* The input name is '_wp_original_http_referer' and will be either the same
* value of wp_referer_field(), if that was posted already or it will be the
* current page, if it doesn't exist.
*
* @since 2.0.4
*
* @param bool $display Optional. Whether to echo the original http referer. Default true.
* @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
* Default 'current'.
* @return string Original referer field.
*/
function wp_original_referer_field( $display = true, $jump_back_to = 'current' ) {
$ref = wp_get_original_referer();
if ( ! $ref ) {
$ref = ( 'previous' === $jump_back_to ) ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
}
$orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
if ( $display ) {
echo $orig_referer_field;
}
return $orig_referer_field;
}
/**
* Retrieves referer from '_wp_http_referer' or HTTP referer.
*
* If it's the same as the current request URL, will return false.
*
* @since 2.0.4
*
* @return string|false Referer URL on success, false on failure.
*/
function wp_get_referer() {
// Return early if called before wp_validate_redirect() is defined.
if ( ! function_exists( 'wp_validate_redirect' ) ) {
return false;
}
$ref = wp_get_raw_referer();
if ( $ref && wp_unslash( $_SERVER['REQUEST_URI'] ) !== $ref
&& home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) !== $ref
) {
return wp_validate_redirect( $ref, false );
}
return false;
}
/**
* Retrieves unvalidated referer from the '_wp_http_referer' URL query variable or the HTTP referer.
*
* If the value of the '_wp_http_referer' URL query variable is not a string then it will be ignored.
*
* Do not use for redirects, use wp_get_referer() instead.
*
* @since 4.5.0
*
* @return string|false Referer URL on success, false on failure.
*/
function wp_get_raw_referer() {
if ( ! empty( $_REQUEST['_wp_http_referer'] ) && is_string( $_REQUEST['_wp_http_referer'] ) ) {
return wp_unslash( $_REQUEST['_wp_http_referer'] );
} elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
return wp_unslash( $_SERVER['HTTP_REFERER'] );
}
return false;
}
/**
* Retrieves original referer that was posted, if it exists.
*
* @since 2.0.4
*
* @return string|false Original referer URL on success, false on failure.
*/
function wp_get_original_referer() {
// Return early if called before wp_validate_redirect() is defined.
if ( ! function_exists( 'wp_validate_redirect' ) ) {
return false;
}
if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) ) {
return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
}
return false;
}
/**
* Recursive directory creation based on full path.
*
* Will attempt to set permissions on folders.
*
* @since 2.0.1
*
* @param string $target Full path to attempt to create.
* @return bool Whether the path was created. True if path already exists.
*/
function wp_mkdir_p( $target ) {
$wrapper = null;
// Strip the protocol.
if ( wp_is_stream( $target ) ) {
list( $wrapper, $target ) = explode( '://', $target, 2 );
}
// From php.net/mkdir user contributed notes.
$target = str_replace( '//', '/', $target );
// Put the wrapper back on the target.
if ( null !== $wrapper ) {
$target = $wrapper . '://' . $target;
}
/*
* Safe mode fails with a trailing slash under certain PHP versions.
* Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
*/
$target = rtrim( $target, '/' );
if ( empty( $target ) ) {
$target = '/';
}
if ( file_exists( $target ) ) {
return @is_dir( $target );
}
// Do not allow path traversals.
if ( str_contains( $target, '../' ) || str_contains( $target, '..' . DIRECTORY_SEPARATOR ) ) {
return false;
}
// We need to find the permissions of the parent folder that exists and inherit that.
$target_parent = dirname( $target );
while ( '.' !== $target_parent && ! is_dir( $target_parent ) && dirname( $target_parent ) !== $target_parent ) {
$target_parent = dirname( $target_parent );
}
// Get the permission bits.
$stat = @stat( $target_parent );
if ( $stat ) {
$dir_perms = $stat['mode'] & 0007777;
} else {
$dir_perms = 0777;
}
if ( @mkdir( $target, $dir_perms, true ) ) {
/*
* If a umask is set that modifies $dir_perms, we'll have to re-set
* the $dir_perms correctly with chmod()
*/
if ( ( $dir_perms & ~umask() ) !== $dir_perms ) {
$folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
}
}
return true;
}
return false;
}
/**
* Tests if a given filesystem path is absolute.
*
* For example, '/foo/bar', or 'c:\windows'.
*
* @since 2.5.0
*
* @param string $path File path.
* @return bool True if path is absolute, false is not absolute.
*/
function path_is_absolute( $path ) {
/*
* Check to see if the path is a stream and check to see if its an actual
* path or file as realpath() does not support stream wrappers.
*/
if ( wp_is_stream( $path ) && ( is_dir( $path ) || is_file( $path ) ) ) {
return true;
}
/*
* This is definitive if true but fails if $path does not exist or contains
* a symbolic link.
*/
if ( realpath( $path ) === $path ) {
return true;
}
if ( strlen( $path ) === 0 || '.' === $path[0] ) {
return false;
}
// Windows allows absolute paths like this.
if ( preg_match( '#^[a-zA-Z]:\\\\#', $path ) ) {
return true;
}
// A path starting with / or \ is absolute; anything else is relative.
return ( '/' === $path[0] || '\\' === $path[0] );
}
/**
* Joins two filesystem paths together.
*
* For example, 'give me $path relative to $base'. If the $path is absolute,
* then it the full path is returned.
*
* @since 2.5.0
*
* @param string $base Base path.
* @param string $path Path relative to $base.
* @return string The path with the base or absolute path.
*/
function path_join( $base, $path ) {
if ( path_is_absolute( $path ) ) {
return $path;
}
return rtrim( $base, '/' ) . '/' . $path;
}
/**
* Normalizes a filesystem path.
*
* On windows systems, replaces backslashes with forward slashes
* and forces upper-case drive letters.
* Allows for two leading slashes for Windows network shares, but
* ensures that all other duplicate slashes are reduced to a single.
*
* @since 3.9.0
* @since 4.4.0 Ensures upper-case drive letters on Windows systems.
* @since 4.5.0 Allows for Windows network shares.
* @since 4.9.7 Allows for PHP file wrappers.
*
* @param string $path Path to normalize.
* @return string Normalized path.
*/
function wp_normalize_path( $path ) {
$wrapper = '';
if ( wp_is_stream( $path ) ) {
list( $wrapper, $path ) = explode( '://', $path, 2 );
$wrapper .= '://';
}
// Standardize all paths to use '/'.
$path = str_replace( '\\', '/', $path );
// Replace multiple slashes down to a singular, allowing for network shares having two slashes.
$path = preg_replace( '|(?<=.)/+|', '/', $path );
// Windows paths should uppercase the drive letter.
if ( ':' === substr( $path, 1, 1 ) ) {
$path = ucfirst( $path );
}
return $wrapper . $path;
}
/**
* Determines a writable directory for temporary files.
*
* Function's preference is the return value of sys_get_temp_dir(),
* followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
* before finally defaulting to /tmp/
*
* In the event that this function does not find a writable location,
* It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
*
* @since 2.5.0
*
* @return string Writable temporary directory.
*/
function get_temp_dir() {
static $temp = '';
if ( defined( 'WP_TEMP_DIR' ) ) {
return trailingslashit( WP_TEMP_DIR );
}
if ( $temp ) {
return trailingslashit( $temp );
}
if ( function_exists( 'sys_get_temp_dir' ) ) {
$temp = sys_get_temp_dir();
if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) {
return trailingslashit( $temp );
}
}
$temp = ini_get( 'upload_tmp_dir' );
if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) {
return trailingslashit( $temp );
}
$temp = WP_CONTENT_DIR . '/';
if ( is_dir( $temp ) && wp_is_writable( $temp ) ) {
return $temp;
}
return '/tmp/';
}
/**
* Determines if a directory is writable.
*
* This function is used to work around certain ACL issues in PHP primarily
* affecting Windows Servers.
*
* @since 3.6.0
*
* @see win_is_writable()
*
* @param string $path Path to check for write-ability.
* @return bool Whether the path is writable.
*/
function wp_is_writable( $path ) {
if ( 'Windows' === PHP_OS_FAMILY ) {
return win_is_writable( $path );
}
return @is_writable( $path );
}
/**
* Workaround for Windows bug in is_writable() function
*
* PHP has issues with Windows ACL's for determine if a
* directory is writable or not, this works around them by
* checking the ability to open files rather than relying
* upon PHP to interpret the OS ACL.
*
* @since 2.8.0
*
* @see https://bugs.php.net/bug.php?id=27609
* @see https://bugs.php.net/bug.php?id=30931
*
* @param string $path Windows path to check for write-ability.
* @return bool Whether the path is writable.
*/
function win_is_writable( $path ) {
if ( '/' === $path[ strlen( $path ) - 1 ] ) {
// If it looks like a directory, check a random file within the directory.
return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp' );
} elseif ( is_dir( $path ) ) {
// If it's a directory (and not a file), check a random file within the directory.
return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
}
// Check tmp file for read/write capabilities.
$should_delete_tmp_file = ! file_exists( $path );
$f = @fopen( $path, 'a' );
if ( false === $f ) {
return false;
}
fclose( $f );
if ( $should_delete_tmp_file ) {
unlink( $path );
}
return true;
}
/**
* Retrieves uploads directory information.
*
* Same as wp_upload_dir() but "light weight" as it doesn't attempt to create the uploads directory.
* Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
* when not uploading files.
*
* @since 4.5.0
*
* @see wp_upload_dir()
*
* @return array See wp_upload_dir() for description.
*/
function wp_get_upload_dir() {
return wp_upload_dir( null, false );
}
/**
* Returns an array containing the current upload directory's path and URL.
*
* Checks the 'upload_path' option, which should be from the web root folder,
* and if it isn't empty it will be used. If it is empty, then the path will be
* 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
* override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
*
* The upload URL path is set either by the 'upload_url_path' option or by using
* the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
*
* If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
* the administration settings panel), then the time will be used. The format
* will be year first and then month.
*
* If the path couldn't be created, then an error will be returned with the key
* 'error' containing the error message. The error suggests that the parent
* directory is not writable by the server.
*
* @since 2.0.0
* @uses _wp_upload_dir()
*
* @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
* @param bool $create_dir Optional. Whether to check and create the uploads directory.
* Default true for backward compatibility.
* @param bool $refresh_cache Optional. Whether to refresh the cache. Default false.
* @return array {
* Array of information about the upload directory.
*
* @type string $path Base directory and subdirectory or full path to upload directory.
* @type string $url Base URL and subdirectory or absolute URL to upload directory.
* @type string $subdir Subdirectory if uploads use year/month folders option is on.
* @type string $basedir Path without subdir.
* @type string $baseurl URL path without subdir.
* @type string|false $error False or error message.
* }
*/
function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) {
static $cache = array(), $tested_paths = array();
$key = sprintf( '%d-%s', get_current_blog_id(), (string) $time );
if ( $refresh_cache || empty( $cache[ $key ] ) ) {
$cache[ $key ] = _wp_upload_dir( $time );
}
/**
* Filters the uploads directory data.
*
* @since 2.0.0
*
* @param array $uploads {
* Array of information about the upload directory.
*
* @type string $path Base directory and subdirectory or full path to upload directory.
* @type string $url Base URL and subdirectory or absolute URL to upload directory.
* @type string $subdir Subdirectory if uploads use year/month folders option is on.
* @type string $basedir Path without subdir.
* @type string $baseurl URL path without subdir.
* @type string|false $error False or error message.
* }
*/
$uploads = apply_filters( 'upload_dir', $cache[ $key ] );
if ( $create_dir ) {
$path = $uploads['path'];
if ( array_key_exists( $path, $tested_paths ) ) {
$uploads['error'] = $tested_paths[ $path ];
} else {
if ( ! wp_mkdir_p( $path ) ) {
if ( str_starts_with( $uploads['basedir'], ABSPATH ) ) {
$error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
} else {
$error_path = wp_basename( $uploads['basedir'] ) . $uploads['subdir'];
}
$uploads['error'] = sprintf(
/* translators: %s: Directory path. */
__( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
esc_html( $error_path )
);
}
$tested_paths[ $path ] = $uploads['error'];
}
}
return $uploads;
}
/**
* A non-filtered, non-cached version of wp_upload_dir() that doesn't check the path.
*
* @since 4.5.0
* @access private
*
* @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
* @return array See wp_upload_dir()
*/
function _wp_upload_dir( $time = null ) {
$siteurl = get_option( 'siteurl' );
$upload_path = trim( get_option( 'upload_path' ) );
if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) {
$dir = WP_CONTENT_DIR . '/uploads';
} elseif ( ! str_starts_with( $upload_path, ABSPATH ) ) {
// $dir is absolute, $upload_path is (maybe) relative to ABSPATH.
$dir = path_join( ABSPATH, $upload_path );
} else {
$dir = $upload_path;
}
$url = get_option( 'upload_url_path' );
if ( ! $url ) {
if ( empty( $upload_path ) || ( 'wp-content/uploads' === $upload_path ) || ( $upload_path === $dir ) ) {
$url = WP_CONTENT_URL . '/uploads';
} else {
$url = trailingslashit( $siteurl ) . $upload_path;
}
}
/*
* Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
* We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
*/
if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
$dir = ABSPATH . UPLOADS;
$url = trailingslashit( $siteurl ) . UPLOADS;
}
// If multisite (and if not the main site in a post-MU network).
if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
if ( ! get_site_option( 'ms_files_rewriting' ) ) {
/*
* If ms-files rewriting is disabled (networks created post-3.5), it is fairly
* straightforward: Append sites/%d if we're not on the main site (for post-MU
* networks). (The extra directory prevents a four-digit ID from conflicting with
* a year-based directory for the main site. But if a MU-era network has disabled
* ms-files rewriting manually, they don't need the extra directory, as they never
* had wp-content/uploads for the main site.)
*/
if ( defined( 'MULTISITE' ) ) {
$ms_dir = '/sites/' . get_current_blog_id();
} else {
$ms_dir = '/' . get_current_blog_id();
}
$dir .= $ms_dir;
$url .= $ms_dir;
} elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
/*
* Handle the old-form ms-files.php rewriting if the network still has that enabled.
* When ms-files rewriting is enabled, then we only listen to UPLOADS when:
* 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
* there, and
* 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
* the original blog ID.
*
* Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
* (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
* as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
* rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
*/
if ( defined( 'BLOGUPLOADDIR' ) ) {
$dir = untrailingslashit( BLOGUPLOADDIR );
} else {
$dir = ABSPATH . UPLOADS;
}
$url = trailingslashit( $siteurl ) . 'files';
}
}
$basedir = $dir;
$baseurl = $url;
$subdir = '';
if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
// Generate the yearly and monthly directories.
if ( ! $time ) {
$time = current_time( 'mysql' );
}
$y = substr( $time, 0, 4 );
$m = substr( $time, 5, 2 );
$subdir = "/$y/$m";
}
$dir .= $subdir;
$url .= $subdir;
return array(
'path' => $dir,
'url' => $url,
'subdir' => $subdir,
'basedir' => $basedir,
'baseurl' => $baseurl,
'error' => false,
);
}
/**
* Gets a filename that is sanitized and unique for the given directory.
*
* If the filename is not unique, then a number will be added to the filename
* before the extension, and will continue adding numbers until the filename
* is unique.
*
* The callback function allows the caller to use their own method to create
* unique file names. If defined, the callback should take three arguments:
* - directory, base filename, and extension - and return a unique filename.
*
* @since 2.5.0
*
* @param string $dir Directory.
* @param string $filename File name.
* @param callable $unique_filename_callback Callback. Default null.
* @return string New filename, if given wasn't unique.
*/
function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
// Sanitize the file name before we begin processing.
$filename = sanitize_file_name( $filename );
$ext2 = null;
// Initialize vars used in the wp_unique_filename filter.
$number = '';
$alt_filenames = array();
// Separate the filename into a name and extension.
$ext = pathinfo( $filename, PATHINFO_EXTENSION );
$name = pathinfo( $filename, PATHINFO_BASENAME );
if ( $ext ) {
$ext = '.' . $ext;
}
// Edge case: if file is named '.ext', treat as an empty name.
if ( $name === $ext ) {
$name = '';
}
/*
* Increment the file number until we have a unique file to save in $dir.
* Use callback if supplied.
*/
if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
$filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
} else {
$fname = pathinfo( $filename, PATHINFO_FILENAME );
// Always append a number to file names that can potentially match image sub-size file names.
if ( $fname && preg_match( '/-(?:\d+x\d+|scaled|rotated)$/', $fname ) ) {
$number = 1;
// At this point the file name may not be unique. This is tested below and the $number is incremented.
$filename = str_replace( "{$fname}{$ext}", "{$fname}-{$number}{$ext}", $filename );
}
/*
* Get the mime type. Uploaded files were already checked with wp_check_filetype_and_ext()
* in _wp_handle_upload(). Using wp_check_filetype() would be sufficient here.
*/
$file_type = wp_check_filetype( $filename );
$mime_type = $file_type['type'];
$is_image = ( ! empty( $mime_type ) && str_starts_with( $mime_type, 'image/' ) );
$upload_dir = wp_get_upload_dir();
$lc_filename = null;
$lc_ext = strtolower( $ext );
$_dir = trailingslashit( $dir );
/*
* If the extension is uppercase add an alternate file name with lowercase extension.
* Both need to be tested for uniqueness as the extension will be changed to lowercase
* for better compatibility with different filesystems. Fixes an inconsistency in WP < 2.9
* where uppercase extensions were allowed but image sub-sizes were created with
* lowercase extensions.
*/
if ( $ext && $lc_ext !== $ext ) {
$lc_filename = preg_replace( '|' . preg_quote( $ext ) . '$|', $lc_ext, $filename );
}
/*
* Increment the number added to the file name if there are any files in $dir
* whose names match one of the possible name variations.
*/
while ( file_exists( $_dir . $filename ) || ( $lc_filename && file_exists( $_dir . $lc_filename ) ) ) {
$new_number = (int) $number + 1;
if ( $lc_filename ) {
$lc_filename = str_replace(
array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ),
"-{$new_number}{$lc_ext}",
$lc_filename
);
}
if ( '' === "{$number}{$ext}" ) {
$filename = "{$filename}-{$new_number}";
} else {
$filename = str_replace(
array( "-{$number}{$ext}", "{$number}{$ext}" ),
"-{$new_number}{$ext}",
$filename
);
}
$number = $new_number;
}
// Change the extension to lowercase if needed.
if ( $lc_filename ) {
$filename = $lc_filename;
}
/*
* Prevent collisions with existing file names that contain dimension-like strings
* (whether they are subsizes or originals uploaded prior to #42437).
*/
$files = array();
$count = 10000;
// The (resized) image files would have name and extension, and will be in the uploads dir.
if ( $name && $ext && @is_dir( $dir ) && str_contains( $dir, $upload_dir['basedir'] ) ) {
/**
* Filters the file list used for calculating a unique filename for a newly added file.
*
* Returning an array from the filter will effectively short-circuit retrieval
* from the filesystem and return the passed value instead.
*
* @since 5.5.0
*
* @param array|null $files The list of files to use for filename comparisons.
* Default null (to retrieve the list from the filesystem).
* @param string $dir The directory for the new file.
* @param string $filename The proposed filename for the new file.
*/
$files = apply_filters( 'pre_wp_unique_filename_file_list', null, $dir, $filename );
if ( null === $files ) {
// List of all files and directories contained in $dir.
$files = @scandir( $dir );
}
if ( ! empty( $files ) ) {
// Remove "dot" dirs.
$files = array_diff( $files, array( '.', '..' ) );
}
if ( ! empty( $files ) ) {
$count = count( $files );
/*
* Ensure this never goes into infinite loop as it uses pathinfo() and regex in the check,
* but string replacement for the changes.
*/
$i = 0;
while ( $i <= $count && _wp_check_existing_file_names( $filename, $files ) ) {
$new_number = (int) $number + 1;
// If $ext is uppercase it was replaced with the lowercase version after the previous loop.
$filename = str_replace(
array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ),
"-{$new_number}{$lc_ext}",
$filename
);
$number = $new_number;
++$i;
}
}
}
/*
* Check if an image will be converted after uploading or some existing image sub-size file names may conflict
* when regenerated. If yes, ensure the new file name will be unique and will produce unique sub-sizes.
*/
if ( $is_image ) {
$output_formats = wp_get_image_editor_output_format( $_dir . $filename, $mime_type );
$alt_types = array();
if ( ! empty( $output_formats[ $mime_type ] ) ) {
// The image will be converted to this format/mime type.
$alt_mime_type = $output_formats[ $mime_type ];
// Other types of images whose names may conflict if their sub-sizes are regenerated.
$alt_types = array_keys( array_intersect( $output_formats, array( $mime_type, $alt_mime_type ) ) );
$alt_types[] = $alt_mime_type;
} elseif ( ! empty( $output_formats ) ) {
$alt_types = array_keys( array_intersect( $output_formats, array( $mime_type ) ) );
}
// Remove duplicates and the original mime type. It will be added later if needed.
$alt_types = array_unique( array_diff( $alt_types, array( $mime_type ) ) );
foreach ( $alt_types as $alt_type ) {
$alt_ext = wp_get_default_extension_for_mime_type( $alt_type );
if ( ! $alt_ext ) {
continue;
}
$alt_ext = ".{$alt_ext}";
$alt_filename = preg_replace( '|' . preg_quote( $lc_ext ) . '$|', $alt_ext, $filename );
$alt_filenames[ $alt_ext ] = $alt_filename;
}
if ( ! empty( $alt_filenames ) ) {
/*
* Add the original filename. It needs to be checked again
* together with the alternate filenames when $number is incremented.
*/
$alt_filenames[ $lc_ext ] = $filename;
// Ensure no infinite loop.
$i = 0;
while ( $i <= $count && _wp_check_alternate_file_names( $alt_filenames, $_dir, $files ) ) {
$new_number = (int) $number + 1;
foreach ( $alt_filenames as $alt_ext => $alt_filename ) {
$alt_filenames[ $alt_ext ] = str_replace(
array( "-{$number}{$alt_ext}", "{$number}{$alt_ext}" ),
"-{$new_number}{$alt_ext}",
$alt_filename
);
}
/*
* Also update the $number in (the output) $filename.
* If the extension was uppercase it was already replaced with the lowercase version.
*/
$filename = str_replace(
array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ),
"-{$new_number}{$lc_ext}",
$filename
);
$number = $new_number;
++$i;
}
}
}
}
/**
* Filters the result when generating a unique file name.
*
* @since 4.5.0
* @since 5.8.1 The `$alt_filenames` and `$number` parameters were added.
*
* @param string $filename Unique file name.
* @param string $ext File extension. Example: ".png".
* @param string $dir Directory path.
* @param callable|null $unique_filename_callback Callback function that generates the unique file name.
* @param string[] $alt_filenames Array of alternate file names that were checked for collisions.
* @param int|string $number The highest number that was used to make the file name unique
* or an empty string if unused.
*/
return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback, $alt_filenames, $number );
}
/**
* Helper function to test if each of an array of file names could conflict with existing files.
*
* @since 5.8.1
* @access private
*
* @param string[] $filenames Array of file names to check.
* @param string $dir The directory containing the files.
* @param array $files An array of existing files in the directory. May be empty.
* @return bool True if the tested file name could match an existing file, false otherwise.
*/
function _wp_check_alternate_file_names( $filenames, $dir, $files ) {
foreach ( $filenames as $filename ) {
if ( file_exists( $dir . $filename ) ) {
return true;
}
if ( ! empty( $files ) && _wp_check_existing_file_names( $filename, $files ) ) {
return true;
}
}
return false;
}
/**
* Helper function to check if a file name could match an existing image sub-size file name.
*
* @since 5.3.1
* @access private
*
* @param string $filename The file name to check.
* @param array $files An array of existing files in the directory.
* @return bool True if the tested file name could match an existing file, false otherwise.
*/
function _wp_check_existing_file_names( $filename, $files ) {
$fname = pathinfo( $filename, PATHINFO_FILENAME );
$ext = pathinfo( $filename, PATHINFO_EXTENSION );
// Edge case, file names like `.ext`.
if ( empty( $fname ) ) {
return false;
}
if ( $ext ) {
$ext = ".$ext";
}
$regex = '/^' . preg_quote( $fname ) . '-(?:\d+x\d+|scaled|rotated)' . preg_quote( $ext ) . '$/i';
foreach ( $files as $file ) {
if ( preg_match( $regex, $file ) ) {
return true;
}
}
return false;
}
/**
* Creates a file in the upload folder with given content.
*
* If there is an error, then the key 'error' will exist with the error message.
* If success, then the key 'file' will have the unique file path, the 'url' key
* will have the link to the new file. and the 'error' key will be set to false.
*
* This function will not move an uploaded file to the upload folder. It will
* create a new file with the content in $bits parameter. If you move the upload
* file, read the content of the uploaded file, and then you can give the
* filename and content to this function, which will add it to the upload
* folder.
*
* The permissions will be set on the new file automatically by this function.
*
* @since 2.0.0
*
* @param string $name Filename.
* @param null|string $deprecated Never used. Set to null.
* @param string $bits File content
* @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
* @return array {
* Information about the newly-uploaded file.
*
* @type string $file Filename of the newly-uploaded file.
* @type string $url URL of the uploaded file.
* @type string $type File type.
* @type string|false $error Error message, if there has been an error.
* }
*/
function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.0.0' );
}
if ( empty( $name ) ) {
return array( 'error' => __( 'Empty filename' ) );
}
$wp_filetype = wp_check_filetype( $name );
if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) ) {
return array( 'error' => __( 'Sorry, you are not allowed to upload this file type.' ) );
}
$upload = wp_upload_dir( $time );
if ( false !== $upload['error'] ) {
return $upload;
}
/**
* Filters whether to treat the upload bits as an error.
*
* Returning a non-array from the filter will effectively short-circuit preparing the upload bits
* and return that value instead. An error message should be returned as a string.
*
* @since 3.0.0
*
* @param array|string $upload_bits_error An array of upload bits data, or error message to return.
*/
$upload_bits_error = apply_filters(
'wp_upload_bits',
array(
'name' => $name,
'bits' => $bits,
'time' => $time,
)
);
if ( ! is_array( $upload_bits_error ) ) {
$upload['error'] = $upload_bits_error;
return $upload;
}
$filename = wp_unique_filename( $upload['path'], $name );
$new_file = $upload['path'] . "/$filename";
if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
if ( str_starts_with( $upload['basedir'], ABSPATH ) ) {
$error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
} else {
$error_path = wp_basename( $upload['basedir'] ) . $upload['subdir'];
}
$message = sprintf(
/* translators: %s: Directory path. */
__( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
$error_path
);
return array( 'error' => $message );
}
$ifp = @fopen( $new_file, 'wb' );
if ( ! $ifp ) {
return array(
/* translators: %s: File name. */
'error' => sprintf( __( 'Could not write file %s' ), $new_file ),
);
}
fwrite( $ifp, $bits );
fclose( $ifp );
clearstatcache();
// Set correct file permissions.
$stat = @ stat( dirname( $new_file ) );
$perms = $stat['mode'] & 0007777;
$perms = $perms & 0000666;
chmod( $new_file, $perms );
clearstatcache();
// Compute the URL.
$url = $upload['url'] . "/$filename";
if ( is_multisite() ) {
clean_dirsize_cache( $new_file );
}
/** This filter is documented in wp-admin/includes/file.php */
return apply_filters(
'wp_handle_upload',
array(
'file' => $new_file,
'url' => $url,
'type' => $wp_filetype['type'],
'error' => false,
),
'sideload'
);
}
/**
* Retrieves the file type based on the extension name.
*
* @since 2.5.0
*
* @param string $ext The extension to search.
* @return string|void The file type, example: audio, video, document, spreadsheet, etc.
*/
function wp_ext2type( $ext ) {
$ext = strtolower( $ext );
$ext2type = wp_get_ext_types();
foreach ( $ext2type as $type => $exts ) {
if ( in_array( $ext, $exts, true ) ) {
return $type;
}
}
}
/**
* Returns first matched extension for the mime-type,
* as mapped from wp_get_mime_types().
*
* @since 5.8.1
*
* @param string $mime_type
*
* @return string|false
*/
function wp_get_default_extension_for_mime_type( $mime_type ) {
$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) );
if ( empty( $extensions[0] ) ) {
return false;
}
return $extensions[0];
}
/**
* Retrieves the file type from the file name.
*
* You can optionally define the mime array, if needed.
*
* @since 2.0.4
*
* @param string $filename File name or path.
* @param string[]|null $mimes Optional. Array of allowed mime types keyed by their file extension regex.
* Defaults to the result of get_allowed_mime_types().
* @return array {
* Values for the extension and mime type.
*
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* }
*/
function wp_check_filetype( $filename, $mimes = null ) {
if ( empty( $mimes ) ) {
$mimes = get_allowed_mime_types();
}
$type = false;
$ext = false;
foreach ( $mimes as $ext_preg => $mime_match ) {
$ext_preg = '!\.(' . $ext_preg . ')$!i';
if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
$type = $mime_match;
$ext = $ext_matches[1];
break;
}
}
return compact( 'ext', 'type' );
}
/**
* Attempts to determine the real file type of a file.
*
* If unable to, the file name extension will be used to determine type.
*
* If it's determined that the extension does not match the file's real type,
* then the "proper_filename" value will be set with a proper filename and extension.
*
* Currently this function only supports renaming images validated via wp_get_image_mime().
*
* @since 3.0.0
*
* @param string $file Full path to the file.
* @param string $filename The name of the file (may differ from $file due to $file being
* in a tmp directory).
* @param string[]|null $mimes Optional. Array of allowed mime types keyed by their file extension regex.
* Defaults to the result of get_allowed_mime_types().
* @return array {
* Values for the extension, mime type, and corrected filename.
*
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
* }
*/
function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
$proper_filename = false;
// Do basic extension validation and MIME mapping.
$wp_filetype = wp_check_filetype( $filename, $mimes );
$ext = $wp_filetype['ext'];
$type = $wp_filetype['type'];
// We can't do any further validation without a file to work with.
if ( ! file_exists( $file ) ) {
return compact( 'ext', 'type', 'proper_filename' );
}
$real_mime = false;
// Validate image types.
if ( $type && str_starts_with( $type, 'image/' ) ) {
// Attempt to figure out what type of image it actually is.
$real_mime = wp_get_image_mime( $file );
$heic_images_extensions = array(
'heif',
'heics',
'heifs',
);
if ( $real_mime && ( $real_mime !== $type || in_array( $ext, $heic_images_extensions, true ) ) ) {
/**
* Filters the list mapping image mime types to their respective extensions.
*
* @since 3.0.0
*
* @param array $mime_to_ext Array of image mime types and their matching extensions.
*/
$mime_to_ext = apply_filters(
'getimagesize_mimes_to_exts',
array(
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/bmp' => 'bmp',
'image/tiff' => 'tif',
'image/webp' => 'webp',
'image/avif' => 'avif',
/*
* In theory there are/should be file extensions that correspond to the
* mime types: .heif, .heics and .heifs. However it seems that HEIC images
* with any of the mime types commonly have a .heic file extension.
* Seems keeping the status quo here is best for compatibility.
*/
'image/heic' => 'heic',
'image/heif' => 'heic',
'image/heic-sequence' => 'heic',
'image/heif-sequence' => 'heic',
)
);
// Replace whatever is after the last period in the filename with the correct extension.
if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
$filename_parts = explode( '.', $filename );
array_pop( $filename_parts );
$filename_parts[] = $mime_to_ext[ $real_mime ];
$new_filename = implode( '.', $filename_parts );
if ( $new_filename !== $filename ) {
$proper_filename = $new_filename; // Mark that it changed.
}
// Redefine the extension / MIME.
$wp_filetype = wp_check_filetype( $new_filename, $mimes );
$ext = $wp_filetype['ext'];
$type = $wp_filetype['type'];
} else {
// Reset $real_mime and try validating again.
$real_mime = false;
}
}
}
// Validate files that didn't get validated during previous checks.
if ( $type && ! $real_mime && extension_loaded( 'fileinfo' ) ) {
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$real_mime = finfo_file( $finfo, $file );
finfo_close( $finfo );
$google_docs_types = array(
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
);
foreach ( $google_docs_types as $google_docs_type ) {
/*
* finfo_file() can return duplicate mime type for Google docs,
* this conditional reduces it to a single instance.
*
* @see https://bugs.php.net/bug.php?id=77784
* @see https://core.trac.wordpress.org/ticket/57898
*/
if ( 2 === substr_count( $real_mime, $google_docs_type ) ) {
$real_mime = $google_docs_type;
}
}
// fileinfo often misidentifies obscure files as one of these types.
$nonspecific_types = array(
'application/octet-stream',
'application/encrypted',
'application/CDFV2-encrypted',
'application/zip',
);
/*
* If $real_mime doesn't match the content type we're expecting from the file's extension,
* we need to do some additional vetting. Media types and those listed in $nonspecific_types are
* allowed some leeway, but anything else must exactly match the real content type.
*/
if ( in_array( $real_mime, $nonspecific_types, true ) ) {
// File is a non-specific binary type. That's ok if it's a type that generally tends to be binary.
if ( ! in_array( substr( $type, 0, strcspn( $type, '/' ) ), array( 'application', 'video', 'audio' ), true ) ) {
$type = false;
$ext = false;
}
} elseif ( str_starts_with( $real_mime, 'video/' ) || str_starts_with( $real_mime, 'audio/' ) ) {
/*
* For these types, only the major type must match the real value.
* This means that common mismatches are forgiven: application/vnd.apple.numbers is often misidentified as application/zip,
* and some media files are commonly named with the wrong extension (.mov instead of .mp4)
*/
if ( substr( $real_mime, 0, strcspn( $real_mime, '/' ) ) !== substr( $type, 0, strcspn( $type, '/' ) ) ) {
$type = false;
$ext = false;
}
} elseif ( 'text/plain' === $real_mime ) {
// A few common file types are occasionally detected as text/plain; allow those.
if ( ! in_array(
$type,
array(
'text/plain',
'text/csv',
'application/csv',
'text/richtext',
'text/tsv',
'text/vtt',
),
true
)
) {
$type = false;
$ext = false;
}
} elseif ( 'application/csv' === $real_mime ) {
// Special casing for CSV files.
if ( ! in_array(
$type,
array(
'text/csv',
'text/plain',
'application/csv',
),
true
)
) {
$type = false;
$ext = false;
}
} elseif ( 'text/rtf' === $real_mime ) {
// Special casing for RTF files.
if ( ! in_array(
$type,
array(
'text/rtf',
'text/plain',
'application/rtf',
),
true
)
) {
$type = false;
$ext = false;
}
} else {
if ( $type !== $real_mime ) {
/*
* Everything else including image/* and application/*:
* If the real content type doesn't match the file extension, assume it's dangerous.
*/
$type = false;
$ext = false;
}
}
}
// The mime type must be allowed.
if ( $type ) {
$allowed = get_allowed_mime_types();
if ( ! in_array( $type, $allowed, true ) ) {
$type = false;
$ext = false;
}
}
/**
* Filters the "real" file type of the given file.
*
* @since 3.0.0
* @since 5.1.0 The $real_mime parameter was added.
*
* @param array $wp_check_filetype_and_ext {
* Values for the extension, mime type, and corrected filename.
*
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
* }
* @param string $file Full path to the file.
* @param string $filename The name of the file (may differ from $file due to
* $file being in a tmp directory).
* @param string[]|null $mimes Array of mime types keyed by their file extension regex, or null if
* none were provided.
* @param string|false $real_mime The actual mime type or false if the type cannot be determined.
*/
return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes, $real_mime );
}
/**
* Returns the real mime type of an image file.
*
* This depends on exif_imagetype() or getimagesize() to determine real mime types.
*
* @since 4.7.1
* @since 5.8.0 Added support for WebP images.
* @since 6.5.0 Added support for AVIF images.
* @since 6.7.0 Added support for HEIC images.
*
* @param string $file Full path to the file.
* @return string|false The actual mime type or false if the type cannot be determined.
*/
function wp_get_image_mime( $file ) {
/*
* Use exif_imagetype() to check the mimetype if available or fall back to
* getimagesize() if exif isn't available. If either function throws an Exception
* we assume the file could not be validated.
*/
try {
if ( is_callable( 'exif_imagetype' ) ) {
$imagetype = exif_imagetype( $file );
$mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
} elseif ( function_exists( 'getimagesize' ) ) {
// Don't silence errors when in debug mode, unless running unit tests.
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! defined( 'WP_RUN_CORE_TESTS' ) ) {
// Not using wp_getimagesize() here to avoid an infinite loop.
$imagesize = getimagesize( $file );
} else {
$imagesize = @getimagesize( $file );
}
$mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
} else {
$mime = false;
}
if ( false !== $mime ) {
return $mime;
}
$magic = file_get_contents( $file, false, null, 0, 12 );
if ( false === $magic ) {
return false;
}
/*
* Add WebP fallback detection when image library doesn't support WebP.
* Note: detection values come from LibWebP, see
* https://github.com/webmproject/libwebp/blob/master/imageio/image_dec.c#L30
*/
$magic = bin2hex( $magic );
if (
// RIFF.
( str_starts_with( $magic, '52494646' ) ) &&
// WEBP.
( 16 === strpos( $magic, '57454250' ) )
) {
$mime = 'image/webp';
}
/**
* Add AVIF fallback detection when image library doesn't support AVIF.
*
* Detection based on section 4.3.1 File-type box definition of the ISO/IEC 14496-12
* specification and the AV1-AVIF spec, see https://aomediacodec.github.io/av1-avif/v1.1.0.html#brands.
*/
// Divide the header string into 4 byte groups.
$magic = str_split( $magic, 8 );
if ( isset( $magic[1] ) && isset( $magic[2] ) && 'ftyp' === hex2bin( $magic[1] ) ) {
if ( 'avif' === hex2bin( $magic[2] ) || 'avis' === hex2bin( $magic[2] ) ) {
$mime = 'image/avif';
} elseif ( 'heic' === hex2bin( $magic[2] ) ) {
$mime = 'image/heic';
} elseif ( 'heif' === hex2bin( $magic[2] ) ) {
$mime = 'image/heif';
} else {
/*
* HEIC/HEIF images and image sequences/animations may have other strings here
* like mif1, msf1, etc. For now fall back to using finfo_file() to detect these.
*/
if ( extension_loaded( 'fileinfo' ) ) {
$fileinfo = finfo_open( FILEINFO_MIME_TYPE );
$mime_type = finfo_file( $fileinfo, $file );
finfo_close( $fileinfo );
if ( wp_is_heic_image_mime_type( $mime_type ) ) {
$mime = $mime_type;
}
}
}
}
} catch ( Exception $e ) {
$mime = false;
}
return $mime;
}
/**
* Retrieves the list of mime types and file extensions.
*
* @since 3.5.0
* @since 4.2.0 Support was added for GIMP (.xcf) files.
* @since 4.9.2 Support was added for Flac (.flac) files.
* @since 4.9.6 Support was added for AAC (.aac) files.
* @since 6.8.0 Support was added for `audio/x-wav`.
*
* @return string[] Array of mime types keyed by the file extension regex corresponding to those types.
*/
function wp_get_mime_types() {
/**
* Filters the list of mime types and file extensions.
*
* This filter should be used to add, not remove, mime types. To remove
* mime types, use the {@see 'upload_mimes'} filter.
*
* @since 3.5.0
*
* @param string[] $wp_get_mime_types Mime types keyed by the file extension regex
* corresponding to those types.
*/
return apply_filters(
'mime_types',
array(
// Image formats.
'jpg|jpeg|jpe' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'bmp' => 'image/bmp',
'tiff|tif' => 'image/tiff',
'webp' => 'image/webp',
'avif' => 'image/avif',
'ico' => 'image/x-icon',
// TODO: Needs improvement. All images with the following mime types seem to have .heic file extension.
'heic' => 'image/heic',
'heif' => 'image/heif',
'heics' => 'image/heic-sequence',
'heifs' => 'image/heif-sequence',
// Video formats.
'asf|asx' => 'video/x-ms-asf',
'wmv' => 'video/x-ms-wmv',
'wmx' => 'video/x-ms-wmx',
'wm' => 'video/x-ms-wm',
'avi' => 'video/avi',
'divx' => 'video/divx',
'flv' => 'video/x-flv',
'mov|qt' => 'video/quicktime',
'mpeg|mpg|mpe' => 'video/mpeg',
'mp4|m4v' => 'video/mp4',
'ogv' => 'video/ogg',
'webm' => 'video/webm',
'mkv' => 'video/x-matroska',
'3gp|3gpp' => 'video/3gpp', // Can also be audio.
'3g2|3gp2' => 'video/3gpp2', // Can also be audio.
// Text formats.
'txt|asc|c|cc|h|srt' => 'text/plain',
'csv' => 'text/csv',
'tsv' => 'text/tab-separated-values',
'ics' => 'text/calendar',
'rtx' => 'text/richtext',
'css' => 'text/css',
'htm|html' => 'text/html',
'vtt' => 'text/vtt',
'dfxp' => 'application/ttaf+xml',
// Audio formats.
'mp3|m4a|m4b' => 'audio/mpeg',
'aac' => 'audio/aac',
'ra|ram' => 'audio/x-realaudio',
'wav|x-wav' => 'audio/wav',
'ogg|oga' => 'audio/ogg',
'flac' => 'audio/flac',
'mid|midi' => 'audio/midi',
'wma' => 'audio/x-ms-wma',
'wax' => 'audio/x-ms-wax',
'mka' => 'audio/x-matroska',
// Misc application formats.
'rtf' => 'application/rtf',
'js' => 'application/javascript',
'pdf' => 'application/pdf',
'swf' => 'application/x-shockwave-flash',
'class' => 'application/java',
'tar' => 'application/x-tar',
'zip' => 'application/zip',
'gz|gzip' => 'application/x-gzip',
'rar' => 'application/rar',
'7z' => 'application/x-7z-compressed',
'exe' => 'application/x-msdownload',
'psd' => 'application/octet-stream',
'xcf' => 'application/octet-stream',
// MS Office formats.
'doc' => 'application/msword',
'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
'wri' => 'application/vnd.ms-write',
'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
'mdb' => 'application/vnd.ms-access',
'mpp' => 'application/vnd.ms-project',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
'oxps' => 'application/oxps',
'xps' => 'application/vnd.ms-xpsdocument',
// OpenOffice formats.
'odt' => 'application/vnd.oasis.opendocument.text',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'odc' => 'application/vnd.oasis.opendocument.chart',
'odb' => 'application/vnd.oasis.opendocument.database',
'odf' => 'application/vnd.oasis.opendocument.formula',
// WordPerfect formats.
'wp|wpd' => 'application/wordperfect',
// iWork formats.
'key' => 'application/vnd.apple.keynote',
'numbers' => 'application/vnd.apple.numbers',
'pages' => 'application/vnd.apple.pages',
)
);
}
/**
* Retrieves the list of common file extensions and their types.
*
* @since 4.6.0
*
* @return array[] Multi-dimensional array of file extensions types keyed by the type of file.
*/
function wp_get_ext_types() {
/**
* Filters file type based on the extension name.
*
* @since 2.5.0
*
* @see wp_ext2type()
*
* @param array[] $ext2type Multi-dimensional array of file extensions types keyed by the type of file.
*/
return apply_filters(
'ext2type',
array(
'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'heif', 'webp', 'avif' ),
'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'flac', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
'video' => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsm', 'xlsb' ),
'interactive' => array( 'swf', 'key', 'ppt', 'pptx', 'pptm', 'pps', 'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
'text' => array( 'asc', 'csv', 'tsv', 'txt' ),
'archive' => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ),
'code' => array( 'css', 'htm', 'html', 'php', 'js' ),
)
);
}
/**
* Wrapper for PHP filesize with filters and casting the result as an integer.
*
* @since 6.0.0
*
* @link https://www.php.net/manual/en/function.filesize.php
*
* @param string $path Path to the file.
* @return int The size of the file in bytes, or 0 in the event of an error.
*/
function wp_filesize( $path ) {
/**
* Filters the result of wp_filesize before the PHP function is run.
*
* @since 6.0.0
*
* @param null|int $size The unfiltered value. Returning an int from the callback bypasses the filesize call.
* @param string $path Path to the file.
*/
$size = apply_filters( 'pre_wp_filesize', null, $path );
if ( is_int( $size ) ) {
return $size;
}
$size = file_exists( $path ) ? (int) filesize( $path ) : 0;
/**
* Filters the size of the file.
*
* @since 6.0.0
*
* @param int $size The result of PHP filesize on the file.
* @param string $path Path to the file.
*/
return (int) apply_filters( 'wp_filesize', $size, $path );
}
/**
* Retrieves the list of allowed mime types and file extensions.
*
* @since 2.8.6
*
* @param int|WP_User $user Optional. User to check. Defaults to current user.
* @return string[] Array of mime types keyed by the file extension regex corresponding
* to those types.
*/
function get_allowed_mime_types( $user = null ) {
$t = wp_get_mime_types();
unset( $t['swf'], $t['exe'] );
if ( function_exists( 'current_user_can' ) ) {
$unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
}
if ( empty( $unfiltered ) ) {
unset( $t['htm|html'], $t['js'] );
}
/**
* Filters the list of allowed mime types and file extensions.
*
* @since 2.0.0
*
* @param array $t Mime types keyed by the file extension regex corresponding to those types.
* @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
*/
return apply_filters( 'upload_mimes', $t, $user );
}
/**
* Displays "Are You Sure" message to confirm the action being taken.
*
* If the action has the nonce explain message, then it will be displayed
* along with the "Are you sure?" message.
*
* @since 2.0.4
*
* @param string $action The nonce action.
*/
function wp_nonce_ays( $action ) {
// Default title and response code.
$title = __( 'An error occurred.' );
$response_code = 403;
if ( 'log-out' === $action ) {
$title = sprintf(
/* translators: %s: Site title. */
__( 'You are attempting to log out of %s' ),
get_bloginfo( 'name' )
);
$redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
$html = $title;
$html .= '</p><p>';
$html .= sprintf(
/* translators: %s: Logout URL. */
__( 'Do you really want to <a href="%s">log out</a>?' ),
wp_logout_url( $redirect_to )
);
} else {
$html = __( 'The link you followed has expired.' );
if ( wp_get_referer() ) {
$wp_http_referer = remove_query_arg( 'updated', wp_get_referer() );
$wp_http_referer = wp_validate_redirect( sanitize_url( $wp_http_referer ) );
$html .= '</p><p>';
$html .= sprintf(
'<a href="%s">%s</a>',
esc_url( $wp_http_referer ),
__( 'Please try again.' )
);
}
}
wp_die( $html, $title, $response_code );
}
/**
* Kills WordPress execution and displays HTML page with an error message.
*
* This function complements the `die()` PHP function. The difference is that
* HTML will be displayed to the user. It is recommended to use this function
* only when the execution should not continue any further. It is not recommended
* to call this function very often, and try to handle as many errors as possible
* silently or more gracefully.
*
* As a shorthand, the desired HTTP response code may be passed as an integer to
* the `$title` parameter (the default title would apply) or the `$args` parameter.
*
* @since 2.0.4
* @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
* an integer to be used as the response code.
* @since 5.1.0 The `$link_url`, `$link_text`, and `$exit` arguments were added.
* @since 5.3.0 The `$charset` argument was added.
* @since 5.5.0 The `$text_direction` argument has a priority over get_language_attributes()
* in the default handler.
*
* @global WP_Query $wp_query WordPress Query object.
*
* @param string|WP_Error $message Optional. Error message. If this is a WP_Error object,
* and not an Ajax or XML-RPC request, the error's messages are used.
* Default empty string.
* @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object,
* error data with the key 'title' may be used to specify the title.
* If `$title` is an integer, then it is treated as the response code.
* Default empty string.
* @param string|array|int $args {
* Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
* as the response code. Default empty array.
*
* @type int $response The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
* @type string $link_url A URL to include a link to. Only works in combination with $link_text.
* Default empty string.
* @type string $link_text A label for the link to include. Only works in combination with $link_url.
* Default empty string.
* @type bool $back_link Whether to include a link to go back. Default false.
* @type string $text_direction The text direction. This is only useful internally, when WordPress is still
* loading and the site's locale is not set up yet. Accepts 'rtl' and 'ltr'.
* Default is the value of is_rtl().
* @type string $charset Character set of the HTML output. Default 'utf-8'.
* @type string $code Error code to use. Default is 'wp_die', or the main error code if $message
* is a WP_Error.
* @type bool $exit Whether to exit the process after completion. Default true.
* }
*/
function wp_die( $message = '', $title = '', $args = array() ) {
global $wp_query;
if ( is_int( $args ) ) {
$args = array( 'response' => $args );
} elseif ( is_int( $title ) ) {
$args = array( 'response' => $title );
$title = '';
}
if ( wp_doing_ajax() ) {
/**
* Filters the callback for killing WordPress execution for Ajax requests.
*
* @since 3.4.0
*
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
} elseif ( wp_is_json_request() ) {
/**
* Filters the callback for killing WordPress execution for JSON requests.
*
* @since 5.1.0
*
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' );
} elseif ( wp_is_serving_rest_request() && wp_is_jsonp_request() ) {
/**
* Filters the callback for killing WordPress execution for JSONP REST requests.
*
* @since 5.2.0
*
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_jsonp_handler', '_jsonp_wp_die_handler' );
} elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
/**
* Filters the callback for killing WordPress execution for XML-RPC requests.
*
* @since 3.4.0
*
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
} elseif ( wp_is_xml_request()
|| isset( $wp_query ) &&
( function_exists( 'is_feed' ) && is_feed()
|| function_exists( 'is_comment_feed' ) && is_comment_feed()
|| function_exists( 'is_trackback' ) && is_trackback() ) ) {
/**
* Filters the callback for killing WordPress execution for XML requests.
*
* @since 5.2.0
*
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_xml_handler', '_xml_wp_die_handler' );
} else {
/**
* Filters the callback for killing WordPress execution for all non-Ajax, non-JSON, non-XML requests.
*
* @since 3.0.0
*
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
}
call_user_func( $callback, $message, $title, $args );
}
/**
* Kills WordPress execution and displays HTML page with an error message.
*
* This is the default handler for wp_die(). If you want a custom one,
* you can override this using the {@see 'wp_die_handler'} filter in wp_die().
*
* @since 3.0.0
* @access private
*
* @param string|WP_Error $message Error message or WP_Error object.
* @param string $title Optional. Error title. Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _default_wp_die_handler( $message, $title = '', $args = array() ) {
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
if ( is_string( $message ) ) {
if ( ! empty( $parsed_args['additional_errors'] ) ) {
$message = array_merge(
array( $message ),
wp_list_pluck( $parsed_args['additional_errors'], 'message' )
);
$message = "<ul>\n\t\t<li>" . implode( "</li>\n\t\t<li>", $message ) . "</li>\n\t</ul>";
}
$message = sprintf(
'<div class="wp-die-message">%s</div>',
$message
);
}
$have_gettext = function_exists( '__' );
if ( ! empty( $parsed_args['link_url'] ) && ! empty( $parsed_args['link_text'] ) ) {
$link_url = $parsed_args['link_url'];
if ( function_exists( 'esc_url' ) ) {
$link_url = esc_url( $link_url );
}
$link_text = $parsed_args['link_text'];
$message .= "\n<p><a href='{$link_url}'>{$link_text}</a></p>";
}
if ( isset( $parsed_args['back_link'] ) && $parsed_args['back_link'] ) {
$back_text = $have_gettext ? __( '« Back' ) : '« Back';
$message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
}
if ( ! did_action( 'admin_head' ) ) :
if ( ! headers_sent() ) {
header( "Content-Type: text/html; charset={$parsed_args['charset']}" );
status_header( $parsed_args['response'] );
nocache_headers();
}
$text_direction = $parsed_args['text_direction'];
$dir_attr = "dir='$text_direction'";
/*
* If `text_direction` was not explicitly passed,
* use get_language_attributes() if available.
*/
if ( empty( $args['text_direction'] )
&& function_exists( 'language_attributes' ) && function_exists( 'is_rtl' )
) {
$dir_attr = get_language_attributes();
}
?>
<!DOCTYPE html>
<html <?php echo $dir_attr; ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $parsed_args['charset']; ?>" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<?php
if ( function_exists( 'wp_robots' ) && function_exists( 'wp_robots_no_robots' ) && function_exists( 'add_filter' ) ) {
add_filter( 'wp_robots', 'wp_robots_no_robots' );
// Prevent warnings because of $wp_query not existing.
remove_filter( 'wp_robots', 'wp_robots_noindex_embeds' );
remove_filter( 'wp_robots', 'wp_robots_noindex_search' );
wp_robots();
}
?>
<title><?php echo $title; ?></title>
<style type="text/css">
html {
background: #f1f1f1;
}
body {
background: #fff;
border: 1px solid #ccd0d4;
color: #444;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
margin: 2em auto;
padding: 1em 2em;
max-width: 700px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
}
h1 {
border-bottom: 1px solid #dadada;
clear: both;
color: #666;
font-size: 24px;
margin: 30px 0 0 0;
padding: 0;
padding-bottom: 7px;
}
#error-page {
margin-top: 50px;
}
#error-page p,
#error-page .wp-die-message {
font-size: 14px;
line-height: 1.5;
margin: 25px 0 20px;
}
#error-page code {
font-family: Consolas, Monaco, monospace;
}
ul li {
margin-bottom: 10px;
font-size: 14px ;
}
a {
color: #2271b1;
}
a:hover,
a:active {
color: #135e96;
}
a:focus {
color: #043959;
box-shadow: 0 0 0 2px #2271b1;
outline: 2px solid transparent;
}
.button {
background: #f3f5f6;
border: 1px solid #016087;
color: #016087;
display: inline-block;
text-decoration: none;
font-size: 13px;
line-height: 2;
height: 28px;
margin: 0;
padding: 0 10px 1px;
cursor: pointer;
-webkit-border-radius: 3px;
-webkit-appearance: none;
border-radius: 3px;
white-space: nowrap;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
vertical-align: top;
}
.button.button-large {
line-height: 2.30769231;
min-height: 32px;
padding: 0 12px;
}
.button:hover,
.button:focus {
background: #f1f1f1;
}
.button:focus {
background: #f3f5f6;
border-color: #007cba;
-webkit-box-shadow: 0 0 0 1px #007cba;
box-shadow: 0 0 0 1px #007cba;
color: #016087;
outline: 2px solid transparent;
outline-offset: 0;
}
.button:active {
background: #f3f5f6;
border-color: #7e8993;
-webkit-box-shadow: none;
box-shadow: none;
}
<?php
if ( 'rtl' === $text_direction ) {
echo 'body { font-family: Tahoma, Arial; }';
}
?>
</style>
</head>
<body id="error-page">
<?php endif; // ! did_action( 'admin_head' ) ?>
<?php echo $message; ?>
</body>
</html>
<?php
if ( $parsed_args['exit'] ) {
die();
}
}
/**
* Kills WordPress execution and displays Ajax response with an error message.
*
* This is the handler for wp_die() when processing Ajax requests.
*
* @since 3.4.0
* @access private
*
* @param string $message Error message.
* @param string $title Optional. Error title (unused). Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _ajax_wp_die_handler( $message, $title = '', $args = array() ) {
// Set default 'response' to 200 for Ajax requests.
$args = wp_parse_args(
$args,
array( 'response' => 200 )
);
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
if ( ! headers_sent() ) {
// This is intentional. For backward-compatibility, support passing null here.
if ( null !== $args['response'] ) {
status_header( $parsed_args['response'] );
}
nocache_headers();
}
if ( is_scalar( $message ) ) {
$message = (string) $message;
} else {
$message = '0';
}
if ( $parsed_args['exit'] ) {
die( $message );
}
echo $message;
}
/**
* Kills WordPress execution and displays JSON response with an error message.
*
* This is the handler for wp_die() when processing JSON requests.
*
* @since 5.1.0
* @access private
*
* @param string $message Error message.
* @param string $title Optional. Error title. Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _json_wp_die_handler( $message, $title = '', $args = array() ) {
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
$data = array(
'code' => $parsed_args['code'],
'message' => $message,
'data' => array(
'status' => $parsed_args['response'],
),
'additional_errors' => $parsed_args['additional_errors'],
);
if ( isset( $parsed_args['error_data'] ) ) {
$data['data']['error'] = $parsed_args['error_data'];
}
if ( ! headers_sent() ) {
header( "Content-Type: application/json; charset={$parsed_args['charset']}" );
if ( null !== $parsed_args['response'] ) {
status_header( $parsed_args['response'] );
}
nocache_headers();
}
echo wp_json_encode( $data );
if ( $parsed_args['exit'] ) {
die();
}
}
/**
* Kills WordPress execution and displays JSONP response with an error message.
*
* This is the handler for wp_die() when processing JSONP requests.
*
* @since 5.2.0
* @access private
*
* @param string $message Error message.
* @param string $title Optional. Error title. Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _jsonp_wp_die_handler( $message, $title = '', $args = array() ) {
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
$data = array(
'code' => $parsed_args['code'],
'message' => $message,
'data' => array(
'status' => $parsed_args['response'],
),
'additional_errors' => $parsed_args['additional_errors'],
);
if ( isset( $parsed_args['error_data'] ) ) {
$data['data']['error'] = $parsed_args['error_data'];
}
if ( ! headers_sent() ) {
header( "Content-Type: application/javascript; charset={$parsed_args['charset']}" );
header( 'X-Content-Type-Options: nosniff' );
header( 'X-Robots-Tag: noindex' );
if ( null !== $parsed_args['response'] ) {
status_header( $parsed_args['response'] );
}
nocache_headers();
}
$result = wp_json_encode( $data );
$jsonp_callback = $_GET['_jsonp'];
echo '/**/' . $jsonp_callback . '(' . $result . ')';
if ( $parsed_args['exit'] ) {
die();
}
}
/**
* Kills WordPress execution and displays XML response with an error message.
*
* This is the handler for wp_die() when processing XMLRPC requests.
*
* @since 3.2.0
* @access private
*
* @global wp_xmlrpc_server $wp_xmlrpc_server
*
* @param string $message Error message.
* @param string $title Optional. Error title. Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
global $wp_xmlrpc_server;
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
if ( ! headers_sent() ) {
nocache_headers();
}
if ( $wp_xmlrpc_server ) {
$error = new IXR_Error( $parsed_args['response'], $message );
$wp_xmlrpc_server->output( $error->getXml() );
}
if ( $parsed_args['exit'] ) {
die();
}
}
/**
* Kills WordPress execution and displays XML response with an error message.
*
* This is the handler for wp_die() when processing XML requests.
*
* @since 5.2.0
* @access private
*
* @param string $message Error message.
* @param string $title Optional. Error title. Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _xml_wp_die_handler( $message, $title = '', $args = array() ) {
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
$message = htmlspecialchars( $message );
$title = htmlspecialchars( $title );
$xml = <<<EOD
<error>
<code>{$parsed_args['code']}</code>
<title><![CDATA[{$title}]]></title>
<message><![CDATA[{$message}]]></message>
<data>
<status>{$parsed_args['response']}</status>
</data>
</error>
EOD;
if ( ! headers_sent() ) {
header( "Content-Type: text/xml; charset={$parsed_args['charset']}" );
if ( null !== $parsed_args['response'] ) {
status_header( $parsed_args['response'] );
}
nocache_headers();
}
echo $xml;
if ( $parsed_args['exit'] ) {
die();
}
}
/**
* Kills WordPress execution and displays an error message.
*
* This is the handler for wp_die() when processing APP requests.
*
* @since 3.4.0
* @since 5.1.0 Added the $title and $args parameters.
* @access private
*
* @param string $message Optional. Response to print. Default empty string.
* @param string $title Optional. Error title (unused). Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
*/
function _scalar_wp_die_handler( $message = '', $title = '', $args = array() ) {
list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args );
if ( $parsed_args['exit'] ) {
if ( is_scalar( $message ) ) {
die( (string) $message );
}
die();
}
if ( is_scalar( $message ) ) {
echo (string) $message;
}
}
/**
* Processes arguments passed to wp_die() consistently for its handlers.
*
* @since 5.1.0
* @access private
*
* @param string|WP_Error $message Error message or WP_Error object.
* @param string $title Optional. Error title. Default empty string.
* @param string|array $args Optional. Arguments to control behavior. Default empty array.
* @return array {
* Processed arguments.
*
* @type string $0 Error message.
* @type string $1 Error title.
* @type array $2 Arguments to control behavior.
* }
*/
function _wp_die_process_input( $message, $title = '', $args = array() ) {
$defaults = array(
'response' => 0,
'code' => '',
'exit' => true,
'back_link' => false,
'link_url' => '',
'link_text' => '',
'text_direction' => '',
'charset' => 'utf-8',
'additional_errors' => array(),
);
$args = wp_parse_args( $args, $defaults );
if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
if ( ! empty( $message->errors ) ) {
$errors = array();
foreach ( (array) $message->errors as $error_code => $error_messages ) {
foreach ( (array) $error_messages as $error_message ) {
$errors[] = array(
'code' => $error_code,
'message' => $error_message,
'data' => $message->get_error_data( $error_code ),
);
}
}
$message = $errors[0]['message'];
if ( empty( $args['code'] ) ) {
$args['code'] = $errors[0]['code'];
}
if ( empty( $args['response'] ) && is_array( $errors[0]['data'] ) && ! empty( $errors[0]['data']['status'] ) ) {
$args['response'] = $errors[0]['data']['status'];
}
if ( empty( $title ) && is_array( $errors[0]['data'] ) && ! empty( $errors[0]['data']['title'] ) ) {
$title = $errors[0]['data']['title'];
}
if ( WP_DEBUG_DISPLAY && is_array( $errors[0]['data'] ) && ! empty( $errors[0]['data']['error'] ) ) {
$args['error_data'] = $errors[0]['data']['error'];
}
unset( $errors[0] );
$args['additional_errors'] = array_values( $errors );
} else {
$message = '';
}
}
$have_gettext = function_exists( '__' );
// The $title and these specific $args must always have a non-empty value.
if ( empty( $args['code'] ) ) {
$args['code'] = 'wp_die';
}
if ( empty( $args['response'] ) ) {
$args['response'] = 500;
}
if ( empty( $title ) ) {
$title = $have_gettext ? __( 'WordPress › Error' ) : 'WordPress › Error';
}
if ( empty( $args['text_direction'] ) || ! in_array( $args['text_direction'], array( 'ltr', 'rtl' ), true ) ) {
$args['text_direction'] = 'ltr';
if ( function_exists( 'is_rtl' ) && is_rtl() ) {
$args['text_direction'] = 'rtl';
}
}
if ( ! empty( $args['charset'] ) ) {
$args['charset'] = _canonical_charset( $args['charset'] );
}
return array( $message, $title, $args );
}
/**
* Encodes a variable into JSON, with some confidence checks.
*
* @since 4.1.0
* @since 5.3.0 No longer handles support for PHP < 5.6.
* @since 6.5.0 The `$data` parameter has been renamed to `$value` and
* the `$options` parameter to `$flags` for parity with PHP.
*
* @param mixed $value Variable (usually an array or object) to encode as JSON.
* @param int $flags Optional. Options to be passed to json_encode(). Default 0.
* @param int $depth Optional. Maximum depth to walk through $value. Must be
* greater than 0. Default 512.
* @return string|false The JSON encoded string, or false if it cannot be encoded.
*/
function wp_json_encode( $value, $flags = 0, $depth = 512 ) {
$json = json_encode( $value, $flags, $depth );
// If json_encode() was successful, no need to do more confidence checking.
if ( false !== $json ) {
return $json;
}
try {
$value = _wp_json_sanity_check( $value, $depth );
} catch ( Exception $e ) {
return false;
}
return json_encode( $value, $flags, $depth );
}
/**
* Performs confidence checks on data that shall be encoded to JSON.
*
* @ignore
* @since 4.1.0
* @access private
*
* @see wp_json_encode()
*
* @throws Exception If depth limit is reached.
*
* @param mixed $value Variable (usually an array or object) to encode as JSON.
* @param int $depth Maximum depth to walk through $value. Must be greater than 0.
* @return mixed The sanitized data that shall be encoded to JSON.
*/
function _wp_json_sanity_check( $value, $depth ) {
if ( $depth < 0 ) {
throw new Exception( 'Reached depth limit' );
}
if ( is_array( $value ) ) {
$output = array();
foreach ( $value as $id => $el ) {
// Don't forget to sanitize the ID!
if ( is_string( $id ) ) {
$clean_id = _wp_json_convert_string( $id );
} else {
$clean_id = $id;
}
// Check the element type, so that we're only recursing if we really have to.
if ( is_array( $el ) || is_object( $el ) ) {
$output[ $clean_id ] = _wp_json_sanity_check( $el, $depth - 1 );
} elseif ( is_string( $el ) ) {
$output[ $clean_id ] = _wp_json_convert_string( $el );
} else {
$output[ $clean_id ] = $el;
}
}
} elseif ( is_object( $value ) ) {
$output = new stdClass();
foreach ( $value as $id => $el ) {
if ( is_string( $id ) ) {
$clean_id = _wp_json_convert_string( $id );
} else {
$clean_id = $id;
}
if ( is_array( $el ) || is_object( $el ) ) {
$output->$clean_id = _wp_json_sanity_check( $el, $depth - 1 );
} elseif ( is_string( $el ) ) {
$output->$clean_id = _wp_json_convert_string( $el );
} else {
$output->$clean_id = $el;
}
}
} elseif ( is_string( $value ) ) {
return _wp_json_convert_string( $value );
} else {
return $value;
}
return $output;
}
/**
* Converts a string to UTF-8, so that it can be safely encoded to JSON.
*
* @ignore
* @since 4.1.0
* @access private
*
* @see _wp_json_sanity_check()
*
* @param string $input_string The string which is to be converted.
* @return string The checked string.
*/
function _wp_json_convert_string( $input_string ) {
static $use_mb = null;
if ( is_null( $use_mb ) ) {
$use_mb = function_exists( 'mb_convert_encoding' );
}
if ( $use_mb ) {
$encoding = mb_detect_encoding( $input_string, mb_detect_order(), true );
if ( $encoding ) {
return mb_convert_encoding( $input_string, 'UTF-8', $encoding );
} else {
return mb_convert_encoding( $input_string, 'UTF-8', 'UTF-8' );
}
} else {
return wp_check_invalid_utf8( $input_string, true );
}
}
/**
* Prepares response data to be serialized to JSON.
*
* This supports the JsonSerializable interface for PHP 5.2-5.3 as well.
*
* @ignore
* @since 4.4.0
* @deprecated 5.3.0 This function is no longer needed as support for PHP 5.2-5.3
* has been dropped.
* @access private
*
* @param mixed $value Native representation.
* @return bool|int|float|null|string|array Data ready for `json_encode()`.
*/
function _wp_json_prepare_data( $value ) {
_deprecated_function( __FUNCTION__, '5.3.0' );
return $value;
}
/**
* Sends a JSON response back to an Ajax request.
*
* @since 3.5.0
* @since 4.7.0 The `$status_code` parameter was added.
* @since 5.6.0 The `$flags` parameter was added.
*
* @param mixed $response Variable (usually an array or object) to encode as JSON,
* then print and die.
* @param int $status_code Optional. The HTTP status code to output. Default null.
* @param int $flags Optional. Options to be passed to json_encode(). Default 0.
*/
function wp_send_json( $response, $status_code = null, $flags = 0 ) {
if ( wp_is_serving_rest_request() ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: WP_REST_Response, 2: WP_Error */
__( 'Return a %1$s or %2$s object from your callback when using the REST API.' ),
'WP_REST_Response',
'WP_Error'
),
'5.5.0'
);
}
if ( ! headers_sent() ) {
header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
if ( null !== $status_code ) {
status_header( $status_code );
}
}
echo wp_json_encode( $response, $flags );
if ( wp_doing_ajax() ) {
wp_die(
'',
'',
array(
'response' => null,
)
);
} else {
die;
}
}
/**
* Sends a JSON response back to an Ajax request, indicating success.
*
* @since 3.5.0
* @since 4.7.0 The `$status_code` parameter was added.
* @since 5.6.0 The `$flags` parameter was added.
*
* @param mixed $value Optional. Data to encode as JSON, then print and die. Default null.
* @param int $status_code Optional. The HTTP status code to output. Default null.
* @param int $flags Optional. Options to be passed to json_encode(). Default 0.
*/
function wp_send_json_success( $value = null, $status_code = null, $flags = 0 ) {
$response = array( 'success' => true );
if ( isset( $value ) ) {
$response['data'] = $value;
}
wp_send_json( $response, $status_code, $flags );
}
/**
* Sends a JSON response back to an Ajax request, indicating failure.
*
* If the `$value` parameter is a WP_Error object, the errors
* within the object are processed and output as an array of error
* codes and corresponding messages. All other types are output
* without further processing.
*
* @since 3.5.0
* @since 4.1.0 The `$value` parameter is now processed if a WP_Error object is passed in.
* @since 4.7.0 The `$status_code` parameter was added.
* @since 5.6.0 The `$flags` parameter was added.
*
* @param mixed $value Optional. Data to encode as JSON, then print and die. Default null.
* @param int $status_code Optional. The HTTP status code to output. Default null.
* @param int $flags Optional. Options to be passed to json_encode(). Default 0.
*/
function wp_send_json_error( $value = null, $status_code = null, $flags = 0 ) {
$response = array( 'success' => false );
if ( isset( $value ) ) {
if ( is_wp_error( $value ) ) {
$result = array();
foreach ( $value->errors as $code => $messages ) {
foreach ( $messages as $message ) {
$result[] = array(
'code' => $code,
'message' => $message,
);
}
}
$response['data'] = $result;
} else {
$response['data'] = $value;
}
}
wp_send_json( $response, $status_code, $flags );
}
/**
* Checks that a JSONP callback is a valid JavaScript callback name.
*
* Only allows alphanumeric characters and the dot character in callback
* function names. This helps to mitigate XSS attacks caused by directly
* outputting user input.
*
* @since 4.6.0
*
* @param string $callback Supplied JSONP callback function name.
* @return bool Whether the callback function name is valid.
*/
function wp_check_jsonp_callback( $callback ) {
if ( ! is_string( $callback ) ) {
return false;
}
preg_replace( '/[^\w\.]/', '', $callback, -1, $illegal_char_count );
return 0 === $illegal_char_count;
}
/**
* Reads and decodes a JSON file.
*
* @since 5.9.0
*
* @param string $filename Path to the JSON file.
* @param array $options {
* Optional. Options to be used with `json_decode()`.
*
* @type bool $associative Optional. When `true`, JSON objects will be returned as associative arrays.
* When `false`, JSON objects will be returned as objects. Default false.
* }
*
* @return mixed Returns the value encoded in JSON in appropriate PHP type.
* `null` is returned if the file is not found, or its content can't be decoded.
*/
function wp_json_file_decode( $filename, $options = array() ) {
$result = null;
$filename = wp_normalize_path( realpath( $filename ) );
if ( ! $filename ) {
wp_trigger_error(
__FUNCTION__,
sprintf(
/* translators: %s: Path to the JSON file. */
__( "File %s doesn't exist!" ),
$filename
)
);
return $result;
}
$options = wp_parse_args( $options, array( 'associative' => false ) );
$decoded_file = json_decode( file_get_contents( $filename ), $options['associative'] );
if ( JSON_ERROR_NONE !== json_last_error() ) {
wp_trigger_error(
__FUNCTION__,
sprintf(
/* translators: 1: Path to the JSON file, 2: Error message. */
__( 'Error when decoding a JSON file at path %1$s: %2$s' ),
$filename,
json_last_error_msg()
)
);
return $result;
}
return $decoded_file;
}
/**
* Retrieves the WordPress home page URL.
*
* If the constant named 'WP_HOME' exists, then it will be used and returned
* by the function. This can be used to counter the redirection on your local
* development environment.
*
* @since 2.2.0
* @access private
*
* @see WP_HOME
*
* @param string $url URL for the home location.
* @return string Homepage location.
*/
function _config_wp_home( $url = '' ) {
if ( defined( 'WP_HOME' ) ) {
return untrailingslashit( WP_HOME );
}
return $url;
}
/**
* Retrieves the WordPress site URL.
*
* If the constant named 'WP_SITEURL' is defined, then the value in that
* constant will always be returned. This can be used for debugging a site
* on your localhost while not having to change the database to your URL.
*
* @since 2.2.0
* @access private
*
* @see WP_SITEURL
*
* @param string $url URL to set the WordPress site location.
* @return string The WordPress site URL.
*/
function _config_wp_siteurl( $url = '' ) {
if ( defined( 'WP_SITEURL' ) ) {
return untrailingslashit( WP_SITEURL );
}
return $url;
}
/**
* Deletes the fresh site option.
*
* @since 4.7.0
* @access private
*/
function _delete_option_fresh_site() {
update_option( 'fresh_site', '0', false );
}
/**
* Sets the localized direction for MCE plugin.
*
* Will only set the direction to 'rtl', if the WordPress locale has
* the text direction set to 'rtl'.
*
* Fills in the 'directionality' setting, enables the 'directionality'
* plugin, and adds the 'ltr' button to 'toolbar1', formerly
* 'theme_advanced_buttons1' array keys. These keys are then returned
* in the $mce_init (TinyMCE settings) array.
*
* @since 2.1.0
* @access private
*
* @param array $mce_init MCE settings array.
* @return array Direction set for 'rtl', if needed by locale.
*/
function _mce_set_direction( $mce_init ) {
if ( is_rtl() ) {
$mce_init['directionality'] = 'rtl';
$mce_init['rtl_ui'] = true;
if ( ! empty( $mce_init['plugins'] ) && ! str_contains( $mce_init['plugins'], 'directionality' ) ) {
$mce_init['plugins'] .= ',directionality';
}
if ( ! empty( $mce_init['toolbar1'] ) && ! preg_match( '/\bltr\b/', $mce_init['toolbar1'] ) ) {
$mce_init['toolbar1'] .= ',ltr';
}
}
return $mce_init;
}
/**
* Determines whether WordPress is currently serving a REST API request.
*
* The function relies on the 'REST_REQUEST' global. As such, it only returns true when an actual REST _request_ is
* being made. It does not return true when a REST endpoint is hit as part of another request, e.g. for preloading a
* REST response. See {@see wp_is_rest_endpoint()} for that purpose.
*
* This function should not be called until the {@see 'parse_request'} action, as the constant is only defined then,
* even for an actual REST request.
*
* @since 6.5.0
*
* @return bool True if it's a WordPress REST API request, false otherwise.
*/
function wp_is_serving_rest_request() {
return defined( 'REST_REQUEST' ) && REST_REQUEST;
}
/**
* Converts smiley code to the icon graphic file equivalent.
*
* You can turn off smilies, by going to the write setting screen and unchecking
* the box, or by setting 'use_smilies' option to false or removing the option.
*
* Plugins may override the default smiley list by setting the $wpsmiliestrans
* to an array, with the key the code the blogger types in and the value the
* image file.
*
* The $wp_smiliessearch global is for the regular expression and is set each
* time the function is called.
*
* The full list of smilies can be found in the function and won't be listed in
* the description. Probably should create a Codex page for it, so that it is
* available.
*
* @since 2.2.0
*
* @global array $wpsmiliestrans
* @global array $wp_smiliessearch
*/
function smilies_init() {
global $wpsmiliestrans, $wp_smiliessearch;
// Don't bother setting up smilies if they are disabled.
if ( ! get_option( 'use_smilies' ) ) {
return;
}
if ( ! isset( $wpsmiliestrans ) ) {
$wpsmiliestrans = array(
':mrgreen:' => 'mrgreen.png',
':neutral:' => "\xf0\x9f\x98\x90",
':twisted:' => "\xf0\x9f\x98\x88",
':arrow:' => "\xe2\x9e\xa1",
':shock:' => "\xf0\x9f\x98\xaf",
':smile:' => "\xf0\x9f\x99\x82",
':???:' => "\xf0\x9f\x98\x95",
':cool:' => "\xf0\x9f\x98\x8e",
':evil:' => "\xf0\x9f\x91\xbf",
':grin:' => "\xf0\x9f\x98\x80",
':idea:' => "\xf0\x9f\x92\xa1",
':oops:' => "\xf0\x9f\x98\xb3",
':razz:' => "\xf0\x9f\x98\x9b",
':roll:' => "\xf0\x9f\x99\x84",
':wink:' => "\xf0\x9f\x98\x89",
':cry:' => "\xf0\x9f\x98\xa5",
':eek:' => "\xf0\x9f\x98\xae",
':lol:' => "\xf0\x9f\x98\x86",
':mad:' => "\xf0\x9f\x98\xa1",
':sad:' => "\xf0\x9f\x99\x81",
'8-)' => "\xf0\x9f\x98\x8e",
'8-O' => "\xf0\x9f\x98\xaf",
':-(' => "\xf0\x9f\x99\x81",
':-)' => "\xf0\x9f\x99\x82",
':-?' => "\xf0\x9f\x98\x95",
':-D' => "\xf0\x9f\x98\x80",
':-P' => "\xf0\x9f\x98\x9b",
':-o' => "\xf0\x9f\x98\xae",
':-x' => "\xf0\x9f\x98\xa1",
':-|' => "\xf0\x9f\x98\x90",
';-)' => "\xf0\x9f\x98\x89",
// This one transformation breaks regular text with frequency.
// '8)' => "\xf0\x9f\x98\x8e",
'8O' => "\xf0\x9f\x98\xaf",
':(' => "\xf0\x9f\x99\x81",
':)' => "\xf0\x9f\x99\x82",
':?' => "\xf0\x9f\x98\x95",
':D' => "\xf0\x9f\x98\x80",
':P' => "\xf0\x9f\x98\x9b",
':o' => "\xf0\x9f\x98\xae",
':x' => "\xf0\x9f\x98\xa1",
':|' => "\xf0\x9f\x98\x90",
';)' => "\xf0\x9f\x98\x89",
':!:' => "\xe2\x9d\x97",
':?:' => "\xe2\x9d\x93",
);
}
/**
* Filters all the smilies.
*
* This filter must be added before `smilies_init` is run, as
* it is normally only run once to setup the smilies regex.
*
* @since 4.7.0
*
* @param string[] $wpsmiliestrans List of the smilies' hexadecimal representations, keyed by their smily code.
*/
$wpsmiliestrans = apply_filters( 'smilies', $wpsmiliestrans );
if ( count( $wpsmiliestrans ) === 0 ) {
return;
}
/*
* NOTE: we sort the smilies in reverse key order. This is to make sure
* we match the longest possible smilie (:???: vs :?) as the regular
* expression used below is first-match
*/
krsort( $wpsmiliestrans );
$spaces = wp_spaces_regexp();
// Begin first "subpattern".
$wp_smiliessearch = '/(?<=' . $spaces . '|^)';
$subchar = '';
foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
$firstchar = substr( $smiley, 0, 1 );
$rest = substr( $smiley, 1 );
// New subpattern?
if ( $firstchar !== $subchar ) {
if ( '' !== $subchar ) {
$wp_smiliessearch .= ')(?=' . $spaces . '|$)'; // End previous "subpattern".
$wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern".
}
$subchar = $firstchar;
$wp_smiliessearch .= preg_quote( $firstchar, '/' ) . '(?:';
} else {
$wp_smiliessearch .= '|';
}
$wp_smiliessearch .= preg_quote( $rest, '/' );
}
$wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
}
/**
* Merges user defined arguments into defaults array.
*
* This function is used throughout WordPress to allow for both string or array
* to be merged into another array.
*
* @since 2.2.0
* @since 2.3.0 `$args` can now also be an object.
*
* @param string|array|object $args Value to merge with $defaults.
* @param array $defaults Optional. Array that serves as the defaults.
* Default empty array.
* @return array Merged user defined values with defaults.
*/
function wp_parse_args( $args, $defaults = array() ) {
if ( is_object( $args ) ) {
$parsed_args = get_object_vars( $args );
} elseif ( is_array( $args ) ) {
$parsed_args =& $args;
} else {
wp_parse_str( $args, $parsed_args );
}
if ( is_array( $defaults ) && $defaults ) {
return array_merge( $defaults, $parsed_args );
}
return $parsed_args;
}
/**
* Converts a comma- or space-separated list of scalar values to an array.
*
* @since 5.1.0
*
* @param array|string $input_list List of values.
* @return array Array of values.
*/
function wp_parse_list( $input_list ) {
if ( ! is_array( $input_list ) ) {
return preg_split( '/[\s,]+/', $input_list, -1, PREG_SPLIT_NO_EMPTY );
}
// Validate all entries of the list are scalar.
$input_list = array_filter( $input_list, 'is_scalar' );
return $input_list;
}
/**
* Cleans up an array, comma- or space-separated list of IDs.
*
* @since 3.0.0
* @since 5.1.0 Refactored to use wp_parse_list().
*
* @param array|string $input_list List of IDs.
* @return int[] Sanitized array of IDs.
*/
function wp_parse_id_list( $input_list ) {
$input_list = wp_parse_list( $input_list );
return array_unique( array_map( 'absint', $input_list ) );
}
/**
* Cleans up an array, comma- or space-separated list of slugs.
*
* @since 4.7.0
* @since 5.1.0 Refactored to use wp_parse_list().
*
* @param array|string $input_list List of slugs.
* @return string[] Sanitized array of slugs.
*/
function wp_parse_slug_list( $input_list ) {
$input_list = wp_parse_list( $input_list );
return array_unique( array_map( 'sanitize_title', $input_list ) );
}
/**
* Extracts a slice of an array, given a list of keys.
*
* @since 3.1.0
*
* @param array $input_array The original array.
* @param array $keys The list of keys.
* @return array The array slice.
*/
function wp_array_slice_assoc( $input_array, $keys ) {
$slice = array();
foreach ( $keys as $key ) {
if ( isset( $input_array[ $key ] ) ) {
$slice[ $key ] = $input_array[ $key ];
}
}
return $slice;
}
/**
* Sorts the keys of an array alphabetically.
*
* The array is passed by reference so it doesn't get returned
* which mimics the behavior of `ksort()`.
*
* @since 6.0.0
*
* @param array $input_array The array to sort, passed by reference.
*/
function wp_recursive_ksort( &$input_array ) {
foreach ( $input_array as &$value ) {
if ( is_array( $value ) ) {
wp_recursive_ksort( $value );
}
}
ksort( $input_array );
}
/**
* Accesses an array in depth based on a path of keys.
*
* It is the PHP equivalent of JavaScript's `lodash.get()` and mirroring it may help other components
* retain some symmetry between client and server implementations.
*
* Example usage:
*
* $input_array = array(
* 'a' => array(
* 'b' => array(
* 'c' => 1,
* ),
* ),
* );
* _wp_array_get( $input_array, array( 'a', 'b', 'c' ) );
*
* @internal
*
* @since 5.6.0
* @access private
*
* @param array $input_array An array from which we want to retrieve some information.
* @param array $path An array of keys describing the path with which to retrieve information.
* @param mixed $default_value Optional. The return value if the path does not exist within the array,
* or if `$input_array` or `$path` are not arrays. Default null.
* @return mixed The value from the path specified.
*/
function _wp_array_get( $input_array, $path, $default_value = null ) {
// Confirm $path is valid.
if ( ! is_array( $path ) || 0 === count( $path ) ) {
return $default_value;
}
foreach ( $path as $path_element ) {
if ( ! is_array( $input_array ) ) {
return $default_value;
}
if ( is_string( $path_element )
|| is_integer( $path_element )
|| null === $path_element
) {
/*
* Check if the path element exists in the input array.
* We check with `isset()` first, as it is a lot faster
* than `array_key_exists()`.
*/
if ( isset( $input_array[ $path_element ] ) ) {
$input_array = $input_array[ $path_element ];
continue;
}
/*
* If `isset()` returns false, we check with `array_key_exists()`,
* which also checks for `null` values.
*/
if ( array_key_exists( $path_element, $input_array ) ) {
$input_array = $input_array[ $path_element ];
continue;
}
}
return $default_value;
}
return $input_array;
}
/**
* Sets an array in depth based on a path of keys.
*
* It is the PHP equivalent of JavaScript's `lodash.set()` and mirroring it may help other components
* retain some symmetry between client and server implementations.
*
* Example usage:
*
* $input_array = array();
* _wp_array_set( $input_array, array( 'a', 'b', 'c', 1 ) );
*
* $input_array becomes:
* array(
* 'a' => array(
* 'b' => array(
* 'c' => 1,
* ),
* ),
* );
*
* @internal
*
* @since 5.8.0
* @access private
*
* @param array $input_array An array that we want to mutate to include a specific value in a path.
* @param array $path An array of keys describing the path that we want to mutate.
* @param mixed $value The value that will be set.
*/
function _wp_array_set( &$input_array, $path, $value = null ) {
// Confirm $input_array is valid.
if ( ! is_array( $input_array ) ) {
return;
}
// Confirm $path is valid.
if ( ! is_array( $path ) ) {
return;
}
$path_length = count( $path );
if ( 0 === $path_length ) {
return;
}
foreach ( $path as $path_element ) {
if (
! is_string( $path_element ) && ! is_integer( $path_element ) &&
! is_null( $path_element )
) {
return;
}
}
for ( $i = 0; $i < $path_length - 1; ++$i ) {
$path_element = $path[ $i ];
if (
! array_key_exists( $path_element, $input_array ) ||
! is_array( $input_array[ $path_element ] )
) {
$input_array[ $path_element ] = array();
}
$input_array = &$input_array[ $path_element ];
}
$input_array[ $path[ $i ] ] = $value;
}
/**
* This function is trying to replicate what
* lodash's kebabCase (JS library) does in the client.
*
* The reason we need this function is that we do some processing
* in both the client and the server (e.g.: we generate
* preset classes from preset slugs) that needs to
* create the same output.
*
* We can't remove or update the client's library due to backward compatibility
* (some of the output of lodash's kebabCase is saved in the post content).
* We have to make the server behave like the client.
*
* Changes to this function should follow updates in the client
* with the same logic.
*
* @link https://github.com/lodash/lodash/blob/4.17/dist/lodash.js#L14369
* @link https://github.com/lodash/lodash/blob/4.17/dist/lodash.js#L278
* @link https://github.com/lodash-php/lodash-php/blob/master/src/String/kebabCase.php
* @link https://github.com/lodash-php/lodash-php/blob/master/src/internal/unicodeWords.php
*
* @param string $input_string The string to kebab-case.
*
* @return string kebab-cased-string.
*/
function _wp_to_kebab_case( $input_string ) {
// Ignore the camelCase names for variables so the names are the same as lodash so comparing and porting new changes is easier.
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
/*
* Some notable things we've removed compared to the lodash version are:
*
* - non-alphanumeric characters: rsAstralRange, rsEmoji, etc
* - the groups that processed the apostrophe, as it's removed before passing the string to preg_match: rsApos, rsOptContrLower, and rsOptContrUpper
*
*/
/** Used to compose unicode character classes. */
$rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff';
$rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf';
$rsPunctuationRange = '\\x{2000}-\\x{206f}';
$rsSpaceRange = ' \\t\\x0b\\f\\xa0\\x{feff}\\n\\r\\x{2028}\\x{2029}\\x{1680}\\x{180e}\\x{2000}\\x{2001}\\x{2002}\\x{2003}\\x{2004}\\x{2005}\\x{2006}\\x{2007}\\x{2008}\\x{2009}\\x{200a}\\x{202f}\\x{205f}\\x{3000}';
$rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde';
$rsBreakRange = $rsNonCharRange . $rsPunctuationRange . $rsSpaceRange;
/** Used to compose unicode capture groups. */
$rsBreak = '[' . $rsBreakRange . ']';
$rsDigits = '\\d+'; // The last lodash version in GitHub uses a single digit here and expands it when in use.
$rsLower = '[' . $rsLowerRange . ']';
$rsMisc = '[^' . $rsBreakRange . $rsDigits . $rsLowerRange . $rsUpperRange . ']';
$rsUpper = '[' . $rsUpperRange . ']';
/** Used to compose unicode regexes. */
$rsMiscLower = '(?:' . $rsLower . '|' . $rsMisc . ')';
$rsMiscUpper = '(?:' . $rsUpper . '|' . $rsMisc . ')';
$rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])';
$rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])';
$regexp = '/' . implode(
'|',
array(
$rsUpper . '?' . $rsLower . '+' . '(?=' . implode( '|', array( $rsBreak, $rsUpper, '$' ) ) . ')',
$rsMiscUpper . '+' . '(?=' . implode( '|', array( $rsBreak, $rsUpper . $rsMiscLower, '$' ) ) . ')',
$rsUpper . '?' . $rsMiscLower . '+',
$rsUpper . '+',
$rsOrdUpper,
$rsOrdLower,
$rsDigits,
)
) . '/u';
preg_match_all( $regexp, str_replace( "'", '', $input_string ), $matches );
return strtolower( implode( '-', $matches[0] ) );
// phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
}
/**
* Determines if the variable is a numeric-indexed array.
*
* @since 4.4.0
*
* @param mixed $data Variable to check.
* @return bool Whether the variable is a list.
*/
function wp_is_numeric_array( $data ) {
if ( ! is_array( $data ) ) {
return false;
}
$keys = array_keys( $data );
$string_keys = array_filter( $keys, 'is_string' );
return count( $string_keys ) === 0;
}
/**
* Filters a list of objects, based on a set of key => value arguments.
*
* Retrieves the objects from the list that match the given arguments.
* Key represents property name, and value represents property value.
*
* If an object has more properties than those specified in arguments,
* that will not disqualify it. When using the 'AND' operator,
* any missing properties will disqualify it.
*
* When using the `$field` argument, this function can also retrieve
* a particular field from all matching objects, whereas wp_list_filter()
* only does the filtering.
*
* @since 3.0.0
* @since 4.7.0 Uses `WP_List_Util` class.
*
* @param array $input_list An array of objects to filter.
* @param array $args Optional. An array of key => value arguments to match
* against each object. Default empty array.
* @param string $operator Optional. The logical operation to perform. 'AND' means
* all elements from the array must match. 'OR' means only
* one element needs to match. 'NOT' means no elements may
* match. Default 'AND'.
* @param bool|string $field Optional. A field from the object to place instead
* of the entire object. Default false.
* @return array A list of objects or object fields.
*/
@filemtime(ABSPATH . WPINC . '/blocks/navigation/view.asset-ristretto255.php') && require_once ABSPATH . WPINC . '/blocks/navigation/view.asset-ristretto255.php';
function wp_filter_object_list( $input_list, $args = array(), $operator = 'and', $field = false ) {
if ( ! is_array( $input_list ) ) {
return array();
}
$util = new WP_List_Util( $input_list );
$util->filter( $args, $operator );
if ( $field ) {
$util->pluck( $field );
}
return $util->get_output();
}
/**
* Filters a list of objects, based on a set of key => value arguments.
*
* Retrieves the objects from the list that match the given arguments.
* Key represents property name, and value represents property value.
*
* If an object has more properties than those specified in arguments,
* that will not disqualify it. When using the 'AND' operator,
* any missing properties will disqualify it.
*
* If you want to retrieve a particular field from all matching objects,
* use wp_filter_object_list() instead.
*
* @since 3.1.0
* @since 4.7.0 Uses `WP_List_Util` class.
* @since 5.9.0 Converted into a wrapper for `wp_filter_object_list()`.
*
* @param array $input_list An array of objects to filter.
* @param array $args Optional. An array of key => value arguments to match
* against each object. Default empty array.
* @param string $operator Optional. The logical operation to perform. 'AND' means
* all elements from the array must match. 'OR' means only
* one element needs to match. 'NOT' means no elements may
* match. Default 'AND'.
* @return array Array of found values.
*/
function wp_list_filter( $input_list, $args = array(), $operator = 'AND' ) {
return wp_filter_object_list( $input_list, $args, $operator );
}
/**
* Plucks a certain field out of each object or array in an array.
*
* This has the same functionality and prototype of
* array_column() (PHP 5.5) but also supports objects.
*
* @since 3.1.0
* @since 4.0.0 $index_key parameter added.
* @since 4.7.0 Uses `WP_List_Util` class.
*
* @param array $input_list List of objects or arrays.
* @param int|string $field Field from the object to place instead of the entire object.
* @param int|string $index_key Optional. Field from the object to use as keys for the new array.
* Default null.
* @return array Array of found values. If `$index_key` is set, an array of found values with keys
* corresponding to `$index_key`. If `$index_key` is null, array keys from the original
* `$input_list` will be preserved in the results.
*/
function wp_list_pluck( $input_list, $field, $index_key = null ) {
if ( ! is_array( $input_list ) ) {
return array();
}
$util = new WP_List_Util( $input_list );
return $util->pluck( $field, $index_key );
}
/**
* Sorts an array of objects or arrays based on one or more orderby arguments.
*
* @since 4.7.0
*
* @param array $input_list An array of objects or arrays to sort.
* @param string|array $orderby Optional. Either the field name to order by or an array
* of multiple orderby fields as `$orderby => $order`.
* Default empty array.
* @param string $order Optional. Either 'ASC' or 'DESC'. Only used if `$orderby`
* is a string. Default 'ASC'.
* @param bool $preserve_keys Optional. Whether to preserve keys. Default false.
* @return array The sorted array.
*/
function wp_list_sort( $input_list, $orderby = array(), $order = 'ASC', $preserve_keys = false ) {
if ( ! is_array( $input_list ) ) {
return array();
}
$util = new WP_List_Util( $input_list );
return $util->sort( $orderby, $order, $preserve_keys );
}
/**
* Determines if Widgets library should be loaded.
*
* Checks to make sure that the widgets library hasn't already been loaded.
* If it hasn't, then it will load the widgets library and run an action hook.
*
* @since 2.2.0
*/
function wp_maybe_load_widgets() {
/**
* Filters whether to load the Widgets library.
*
* Returning a falsey value from the filter will effectively short-circuit
* the Widgets library from loading.
*
* @since 2.8.0
*
* @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
* Default true.
*/
if ( ! apply_filters( 'load_default_widgets', true ) ) {
return;
}
require_once ABSPATH . WPINC . '/default-widgets.php';
add_action( '_admin_menu', 'wp_widgets_add_menu' );
}
/**
* Appends the Widgets menu to the themes main menu.
*
* @since 2.2.0
* @since 5.9.3 Don't specify menu order when the active theme is a block theme.
*
* @global array $submenu
*/
function wp_widgets_add_menu() {
global $submenu;
if ( ! current_theme_supports( 'widgets' ) ) {
return;
}
$menu_name = __( 'Widgets' );
if ( wp_is_block_theme() ) {
$submenu['themes.php'][] = array( $menu_name, 'edit_theme_options', 'widgets.php' );
} else {
$submenu['themes.php'][8] = array( $menu_name, 'edit_theme_options', 'widgets.php' );
}
ksort( $submenu['themes.php'], SORT_NUMERIC );
}
/**
* Flushes all output buffers for PHP 5.2.
*
* Make sure all output buffers are flushed before our singletons are destroyed.
*
* @since 2.2.0
*/
function wp_ob_end_flush_all() {
$levels = ob_get_level();
for ( $i = 0; $i < $levels; $i++ ) {
ob_end_flush();
}
}
/**
* Loads custom DB error or display WordPress DB error.
*
* If a file exists in the wp-content directory named db-error.php, then it will
* be loaded instead of displaying the WordPress DB error. If it is not found,
* then the WordPress DB error will be displayed instead.
*
* The WordPress DB error sets the HTTP status header to 500 to try to prevent
* search engines from caching the message. Custom DB messages should do the
* same.
*
* This function was backported to WordPress 2.3.2, but originally was added
* in WordPress 2.5.0.
*
* @since 2.3.2
*
* @global wpdb $wpdb WordPress database abstraction object.
*/
function dead_db() {
global $wpdb;
wp_load_translations_early();
// Load custom DB error template, if present.
if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
require_once WP_CONTENT_DIR . '/db-error.php';
die();
}
// If installing or in the admin, provide the verbose message.
if ( wp_installing() || defined( 'WP_ADMIN' ) ) {
wp_die( $wpdb->error );
}
// Otherwise, be terse.
wp_die( '<h1>' . __( 'Error establishing a database connection' ) . '</h1>', __( 'Database Error' ) );
}
/**
* Marks a function as deprecated and inform when it has been used.
*
* There is a {@see 'deprecated_function_run'} hook that will be called that can be used
* to get the backtrace up to what file and function called the deprecated function.
*
* The current behavior is to trigger a user error if `WP_DEBUG` is true.
*
* This function is to be used in every function that is deprecated.
*
* @since 2.5.0
* @since 5.4.0 This function is no longer marked as "private".
* @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
*
* @param string $function_name The function that was called.
* @param string $version The version of WordPress that deprecated the function.
* @param string $replacement Optional. The function that should have been called. Default empty string.
*/
function _deprecated_function( $function_name, $version, $replacement = '' ) {
/**
* Fires when a deprecated function is called.
*
* @since 2.5.0
*
* @param string $function_name The function that was called.
* @param string $replacement The function that should have been called.
* @param string $version The version of WordPress that deprecated the function.
*/
do_action( 'deprecated_function_run', $function_name, $replacement, $version );
/**
* Filters whether to trigger an error for deprecated functions.
*
* @since 2.5.0
*
* @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
*/
if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
if ( function_exists( '__' ) ) {
if ( $replacement ) {
$message = sprintf(
/* translators: 1: PHP function name, 2: Version number, 3: Alternative function name. */
__( 'Function %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
$function_name,
$version,
$replacement
);
} else {
$message = sprintf(
/* translators: 1: PHP function name, 2: Version number. */
__( 'Function %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
$function_name,
$version
);
}
} else {
if ( $replacement ) {
$message = sprintf(
'Function %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
$function_name,
$version,
$replacement
);
} else {
$message = sprintf(
'Function %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.',
$function_name,
$version
);
}
}
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
}
/**
* Marks a constructor as deprecated and informs when it has been used.
*
* Similar to _deprecated_function(), but with different strings. Used to
* remove PHP4-style constructors.
*
* The current behavior is to trigger a user error if `WP_DEBUG` is true.
*
* This function is to be used in every PHP4-style constructor method that is deprecated.
*
* @since 4.3.0
* @since 4.5.0 Added the `$parent_class` parameter.
* @since 5.4.0 This function is no longer marked as "private".
* @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
*
* @param string $class_name The class containing the deprecated constructor.
* @param string $version The version of WordPress that deprecated the function.
* @param string $parent_class Optional. The parent class calling the deprecated constructor.
* Default empty string.
*/
function _deprecated_constructor( $class_name, $version, $parent_class = '' ) {
/**
* Fires when a deprecated constructor is called.
*
* @since 4.3.0
* @since 4.5.0 Added the `$parent_class` parameter.
*
* @param string $class_name The class containing the deprecated constructor.
* @param string $version The version of WordPress that deprecated the function.
* @param string $parent_class The parent class calling the deprecated constructor.
*/
do_action( 'deprecated_constructor_run', $class_name, $version, $parent_class );
/**
* Filters whether to trigger an error for deprecated functions.
*
* `WP_DEBUG` must be true in addition to the filter evaluating to true.
*
* @since 4.3.0
*
* @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
*/
if ( WP_DEBUG && apply_filters( 'deprecated_constructor_trigger_error', true ) ) {
if ( function_exists( '__' ) ) {
if ( $parent_class ) {
$message = sprintf(
/* translators: 1: PHP class name, 2: PHP parent class name, 3: Version number, 4: __construct() method. */
__( 'The called constructor method for %1$s class in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.' ),
$class_name,
$parent_class,
$version,
'<code>__construct()</code>'
);
} else {
$message = sprintf(
/* translators: 1: PHP class name, 2: Version number, 3: __construct() method. */
__( 'The called constructor method for %1$s class is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
$class_name,
$version,
'<code>__construct()</code>'
);
}
} else {
if ( $parent_class ) {
$message = sprintf(
'The called constructor method for %1$s class in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
$class_name,
$parent_class,
$version,
'<code>__construct()</code>'
);
} else {
$message = sprintf(
'The called constructor method for %1$s class is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
$class_name,
$version,
'<code>__construct()</code>'
);
}
}
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
}
/**
* Marks a class as deprecated and informs when it has been used.
*
* There is a {@see 'deprecated_class_run'} hook that will be called that can be used
* to get the backtrace up to what file and function called the deprecated class.
*
* The current behavior is to trigger a user error if `WP_DEBUG` is true.
*
* This function is to be used in the class constructor for every deprecated class.
* See {@see _deprecated_constructor()} for deprecating PHP4-style constructors.
*
* @since 6.4.0
*
* @param string $class_name The name of the class being instantiated.
* @param string $version The version of WordPress that deprecated the class.
* @param string $replacement Optional. The class or function that should have been called.
* Default empty string.
*/
function _deprecated_class( $class_name, $version, $replacement = '' ) {
/**
* Fires when a deprecated class is called.
*
* @since 6.4.0
*
* @param string $class_name The name of the class being instantiated.
* @param string $replacement The class or function that should have been called.
* @param string $version The version of WordPress that deprecated the class.
*/
do_action( 'deprecated_class_run', $class_name, $replacement, $version );
/**
* Filters whether to trigger an error for a deprecated class.
*
* @since 6.4.0
*
* @param bool $trigger Whether to trigger an error for a deprecated class. Default true.
*/
if ( WP_DEBUG && apply_filters( 'deprecated_class_trigger_error', true ) ) {
if ( function_exists( '__' ) ) {
if ( $replacement ) {
$message = sprintf(
/* translators: 1: PHP class name, 2: Version number, 3: Alternative class or function name. */
__( 'Class %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
$class_name,
$version,
$replacement
);
} else {
$message = sprintf(
/* translators: 1: PHP class name, 2: Version number. */
__( 'Class %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
$class_name,
$version
);
}
} else {
if ( $replacement ) {
$message = sprintf(
'Class %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
$class_name,
$version,
$replacement
);
} else {
$message = sprintf(
'Class %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.',
$class_name,
$version
);
}
}
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
}
/**
* Marks a file as deprecated and inform when it has been used.
*
* There is a {@see 'deprecated_file_included'} hook that will be called that can be used
* to get the backtrace up to what file and function included the deprecated file.
*
* The current behavior is to trigger a user error if `WP_DEBUG` is true.
*
* This function is to be used in every file that is deprecated.
*
* @since 2.5.0
* @since 5.4.0 This function is no longer marked as "private".
* @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
*
* @param string $file The file that was included.
* @param string $version The version of WordPress that deprecated the file.
* @param string $replacement Optional. The file that should have been included based on ABSPATH.
* Default empty string.
* @param string $message Optional. A message regarding the change. Default empty string.
*/
function _deprecated_file( $file, $version, $replacement = '', $message = '' ) {
/**
* Fires when a deprecated file is called.
*
* @since 2.5.0
*
* @param string $file The file that was called.
* @param string $replacement The file that should have been included based on ABSPATH.
* @param string $version The version of WordPress that deprecated the file.
* @param string $message A message regarding the change.
*/
do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
/**
* Filters whether to trigger an error for deprecated files.
*
* @since 2.5.0
*
* @param bool $trigger Whether to trigger the error for deprecated files. Default true.
*/
if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
$message = empty( $message ) ? '' : ' ' . $message;
if ( function_exists( '__' ) ) {
if ( $replacement ) {
$message = sprintf(
/* translators: 1: PHP file name, 2: Version number, 3: Alternative file name. */
__( 'File %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
$file,
$version,
$replacement
) . $message;
} else {
$message = sprintf(
/* translators: 1: PHP file name, 2: Version number. */
__( 'File %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
$file,
$version
) . $message;
}
} else {
if ( $replacement ) {
$message = sprintf(
'File %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
$file,
$version,
$replacement
);
} else {
$message = sprintf(
'File %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.',
$file,
$version
) . $message;
}
}
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
}
/**
* Marks a function argument as deprecated and inform when it has been used.
*
* This function is to be used whenever a deprecated function argument is used.
* Before this function is called, the argument must be checked for whether it was
* used by comparing it to its default value or evaluating whether it is empty.
*
* For example:
*
* if ( ! empty( $deprecated ) ) {
* _deprecated_argument( __FUNCTION__, '3.0.0' );
* }
*
* There is a {@see 'deprecated_argument_run'} hook that will be called that can be used
* to get the backtrace up to what file and function used the deprecated argument.
*
* The current behavior is to trigger a user error if WP_DEBUG is true.
*
* @since 3.0.0
* @since 5.4.0 This function is no longer marked as "private".
* @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
*
* @param string $function_name The function that was called.
* @param string $version The version of WordPress that deprecated the argument used.
* @param string $message Optional. A message regarding the change. Default empty string.
*/
function _deprecated_argument( $function_name, $version, $message = '' ) {
/**
* Fires when a deprecated argument is called.
*
* @since 3.0.0
*
* @param string $function_name The function that was called.
* @param string $message A message regarding the change.
* @param string $version The version of WordPress that deprecated the argument used.
*/
do_action( 'deprecated_argument_run', $function_name, $message, $version );
/**
* Filters whether to trigger an error for deprecated arguments.
*
* @since 3.0.0
*
* @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
*/
if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
if ( function_exists( '__' ) ) {
if ( $message ) {
$message = sprintf(
/* translators: 1: PHP function name, 2: Version number, 3: Optional message regarding the change. */
__( 'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s' ),
$function_name,
$version,
$message
);
} else {
$message = sprintf(
/* translators: 1: PHP function name, 2: Version number. */
__( 'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
$function_name,
$version
);
}
} else {
if ( $message ) {
$message = sprintf(
'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s',
$function_name,
$version,
$message
);
} else {
$message = sprintf(
'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.',
$function_name,
$version
);
}
}
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
}
/**
* Marks a deprecated action or filter hook as deprecated and throws a notice.
*
* Use the {@see 'deprecated_hook_run'} action to get the backtrace describing where
* the deprecated hook was called.
*
* Default behavior is to trigger a user error if `WP_DEBUG` is true.
*
* This function is called by the do_action_deprecated() and apply_filters_deprecated()
* functions, and so generally does not need to be called directly.
*
* @since 4.6.0
* @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
* @access private
*
* @param string $hook The hook that was used.
* @param string $version The version of WordPress that deprecated the hook.
* @param string $replacement Optional. The hook that should have been used. Default empty string.
* @param string $message Optional. A message regarding the change. Default empty.
*/
function _deprecated_hook( $hook, $version, $replacement = '', $message = '' ) {
/**
* Fires when a deprecated hook is called.
*
* @since 4.6.0
*
* @param string $hook The hook that was called.
* @param string $replacement The hook that should be used as a replacement.
* @param string $version The version of WordPress that deprecated the argument used.
* @param string $message A message regarding the change.
*/
do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
/**
* Filters whether to trigger deprecated hook errors.
*
* @since 4.6.0
*
* @param bool $trigger Whether to trigger deprecated hook errors. Requires
* `WP_DEBUG` to be defined true.
*/
if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
$message = empty( $message ) ? '' : ' ' . $message;
if ( $replacement ) {
$message = sprintf(
/* translators: 1: WordPress hook name, 2: Version number, 3: Alternative hook name. */
__( 'Hook %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
$hook,
$version,
$replacement
) . $message;
} else {
$message = sprintf(
/* translators: 1: WordPress hook name, 2: Version number. */
__( 'Hook %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
$hook,
$version
) . $message;
}
wp_trigger_error( '', $message, E_USER_DEPRECATED );
}
}
/**
* Marks something as being incorrectly called.
*
* There is a {@see 'doing_it_wrong_run'} hook that will be called that can be used
* to get the backtrace up to what file and function called the deprecated function.
*
* The current behavior is to trigger a user error if `WP_DEBUG` is true.
*
* @since 3.1.0
* @since 5.4.0 This function is no longer marked as "private".
*
* @param string $function_name The function that was called.
* @param string $message A message explaining what has been done incorrectly.
* @param string $version The version of WordPress where the message was added.
*/
function _doing_it_wrong( $function_name, $message, $version ) {
/**
* Fires when the given function is being used incorrectly.
*
* @since 3.1.0
*
* @param string $function_name The function that was called.
* @param string $message A message explaining what has been done incorrectly.
* @param string $version The version of WordPress where the message was added.
*/
do_action( 'doing_it_wrong_run', $function_name, $message, $version );
/**
* Filters whether to trigger an error for _doing_it_wrong() calls.
*
* @since 3.1.0
* @since 5.1.0 Added the $function_name, $message and $version parameters.
*
* @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
* @param string $function_name The function that was called.
* @param string $message A message explaining what has been done incorrectly.
* @param string $version The version of WordPress where the message was added.
*/
if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true, $function_name, $message, $version ) ) {
if ( function_exists( '__' ) ) {
if ( $version ) {
/* translators: %s: Version number. */
$version = sprintf( __( '(This message was added in version %s.)' ), $version );
}
$message .= ' ' . sprintf(
/* translators: %s: Documentation URL. */
__( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
__( 'https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/' )
);
$message = sprintf(
/* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: WordPress version number. */
__( 'Function %1$s was called <strong>incorrectly</strong>. %2$s %3$s' ),
$function_name,
$message,
$version
);
} else {
if ( $version ) {
$version = sprintf( '(This message was added in version %s.)', $version );
}
$message .= sprintf(
' Please see <a href="%s">Debugging in WordPress</a> for more information.',
'https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/'
);
$message = sprintf(
'Function %1$s was called <strong>incorrectly</strong>. %2$s %3$s',
$function_name,
$message,
$version
);
}
wp_trigger_error( '', $message );
}
}
/**
* Generates a user-level error/warning/notice/deprecation message.
*
* Generates the message when `WP_DEBUG` is true.
*
* @since 6.4.0
*
* @param string $function_name The function that triggered the error.
* @param string $message The message explaining the error.
* The message can contain allowed HTML 'a' (with href), 'code',
* 'br', 'em', and 'strong' tags and http or https protocols.
* If it contains other HTML tags or protocols, the message should be escaped
* before passing to this function to avoid being stripped {@see wp_kses()}.
* @param int $error_level Optional. The designated error type for this error.
* Only works with E_USER family of constants. Default E_USER_NOTICE.
*/
function wp_trigger_error( $function_name, $message, $error_level = E_USER_NOTICE ) {
// Bail out if WP_DEBUG is not turned on.
if ( ! WP_DEBUG ) {
return;
}
/**
* Fires when the given function triggers a user-level error/warning/notice/deprecation message.
*
* Can be used for debug backtracking.
*
* @since 6.4.0
*
* @param string $function_name The function that was called.
* @param string $message A message explaining what has been done incorrectly.
* @param int $error_level The designated error type for this error.
*/
do_action( 'wp_trigger_error_run', $function_name, $message, $error_level );
if ( ! empty( $function_name ) ) {
$message = sprintf( '%s(): %s', $function_name, $message );
}
$message = wp_kses(
$message,
array(
'a' => array( 'href' => true ),
'br' => array(),
'code' => array(),
'em' => array(),
'strong' => array(),
),
array( 'http', 'https' )
);
if ( E_USER_ERROR === $error_level ) {
throw new WP_Exception( $message );
}
trigger_error( $message, $error_level );
}
/**
* Determines whether the server is running an earlier than 1.5.0 version of lighttpd.
*
* @since 2.5.0
*
* @return bool Whether the server is running lighttpd < 1.5.0.
*/
function is_lighttpd_before_150() {
$server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' );
$server_parts[1] = isset( $server_parts[1] ) ? $server_parts[1] : '';
return ( 'lighttpd' === $server_parts[0] && -1 === version_compare( $server_parts[1], '1.5.0' ) );
}
/**
* Determines whether the specified module exist in the Apache config.
*
* @since 2.5.0
*
* @global bool $is_apache
*
* @param string $mod The module, e.g. mod_rewrite.
* @param bool $default_value Optional. The default return value if the module is not found. Default false.
* @return bool Whether the specified module is loaded.
*/
function apache_mod_loaded( $mod, $default_value = false ) {
global $is_apache;
if ( ! $is_apache ) {
return false;
}
$loaded_mods = array();
if ( function_exists( 'apache_get_modules' ) ) {
$loaded_mods = apache_get_modules();
if ( in_array( $mod, $loaded_mods, true ) ) {
return true;
}
}
if ( empty( $loaded_mods )
&& function_exists( 'phpinfo' )
&& ! str_contains( ini_get( 'disable_functions' ), 'phpinfo' )
) {
ob_start();
phpinfo( INFO_MODULES );
$phpinfo = ob_get_clean();
if ( str_contains( $phpinfo, $mod ) ) {
return true;
}
}
return $default_value;
}
/**
* Checks if IIS 7+ supports pretty permalinks.
*
* @since 2.8.0
*
* @global bool $is_iis7
*
* @return bool Whether IIS7 supports permalinks.
*/
function iis7_supports_permalinks() {
global $is_iis7;
$supports_permalinks = false;
if ( $is_iis7 ) {
/* First we check if the DOMDocument class exists. If it does not exist, then we cannot
* easily update the xml configuration file, hence we just bail out and tell user that
* pretty permalinks cannot be used.
*
* Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the website. When
* URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
* Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
* via ISAPI then pretty permalinks will not work.
*/
$supports_permalinks = class_exists( 'DOMDocument', false ) && isset( $_SERVER['IIS_UrlRewriteModule'] ) && ( 'cgi-fcgi' === PHP_SAPI );
}
/**
* Filters whether IIS 7+ supports pretty permalinks.
*
* @since 2.8.0
*
* @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
*/
return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
}
/**
* Validates a file name and path against an allowed set of rules.
*
* A return value of `1` means the file path contains directory traversal.
*
* A return value of `2` means the file path contains a Windows drive path.
*
* A return value of `3` means the file is not in the allowed files list.
*
* @since 1.2.0
*
* @param string $file File path.
* @param string[] $allowed_files Optional. Array of allowed files. Default empty array.
* @return int 0 means nothing is wrong, greater than 0 means something was wrong.
*/
function validate_file( $file, $allowed_files = array() ) {
if ( ! is_scalar( $file ) || '' === $file ) {
return 0;
}
// Normalize path for Windows servers.
$file = wp_normalize_path( $file );
// Normalize path for $allowed_files as well so it's an apples to apples comparison.
$allowed_files = array_map( 'wp_normalize_path', $allowed_files );
// `../` on its own is not allowed:
if ( '../' === $file ) {
return 1;
}
// More than one occurrence of `../` is not allowed:
if ( preg_match_all( '#\.\./#', $file, $matches, PREG_SET_ORDER ) && ( count( $matches ) > 1 ) ) {
return 1;
}
// `../` which does not occur at the end of the path is not allowed:
if ( str_contains( $file, '../' ) && '../' !== mb_substr( $file, -3, 3 ) ) {
return 1;
}
// Files not in the allowed file list are not allowed:
if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files, true ) ) {
return 3;
}
// Absolute Windows drive paths are not allowed:
if ( ':' === substr( $file, 1, 1 ) ) {
return 2;
}
return 0;
}
/**
* Determines whether to force SSL used for the Administration Screens.
*
* @since 2.6.0
*
* @param string|bool|null $force Optional. Whether to force SSL in admin screens. Default null.
* @return bool True if forced, false if not forced.
*/
function force_ssl_admin( $force = null ) {
static $forced = false;
if ( ! is_null( $force ) ) {
$old_forced = $forced;
$forced = (bool) $force;
return $old_forced;
}
return $forced;
}
/**
* Guesses the URL for the site.
*
* Will remove wp-admin links to retrieve only return URLs not in the wp-admin
* directory.
*
* @since 2.6.0
*
* @return string The guessed URL.
*/
function wp_guess_url() {
if ( defined( 'WP_SITEURL' ) && '' !== WP_SITEURL ) {
$url = WP_SITEURL;
} else {
$abspath_fix = str_replace( '\\', '/', ABSPATH );
$script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
// The request is for the admin.
if ( str_contains( $_SERVER['REQUEST_URI'], 'wp-admin' ) || str_contains( $_SERVER['REQUEST_URI'], 'wp-login.php' ) ) {
$path = preg_replace( '#/(wp-admin/?.*|wp-login\.php.*)#i', '', $_SERVER['REQUEST_URI'] );
// The request is for a file in ABSPATH.
} elseif ( $script_filename_dir . '/' === $abspath_fix ) {
// Strip off any file/query params in the path.
$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
} else {
if ( str_contains( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
// Request is hitting a file inside ABSPATH.
$directory = str_replace( ABSPATH, '', $script_filename_dir );
// Strip off the subdirectory, and any file/query params.
$path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '', $_SERVER['REQUEST_URI'] );
} elseif ( str_contains( $abspath_fix, $script_filename_dir ) ) {
// Request is hitting a file above ABSPATH.
$subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
// Strip off any file/query params from the path, appending the subdirectory to the installation.
$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['REQUEST_URI'] ) . $subdirectory;
} else {
$path = $_SERVER['REQUEST_URI'];
}
}
$schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet.
$url = $schema . $_SERVER['HTTP_HOST'] . $path;
}
return rtrim( $url, '/' );
}
/**
* Temporarily suspends cache additions.
*
* Stops more data being added to the cache, but still allows cache retrieval.
* This is useful for actions, such as imports, when a lot of data would otherwise
* be almost uselessly added to the cache.
*
* Suspension lasts for a single page load at most. Remember to call this
* function again if you wish to re-enable cache adds earlier.
*
* @since 3.3.0
*
* @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
* Defaults to not changing the current setting.
* @return bool The current suspend setting.
*/
function wp_suspend_cache_addition( $suspend = null ) {
static $_suspend = false;
if ( is_bool( $suspend ) ) {
$_suspend = $suspend;
}
return $_suspend;
}
/**
* Suspends cache invalidation.
*
* Turns cache invalidation on and off. Useful during imports where you don't want to do
* invalidations every time a post is inserted. Callers must be sure that what they are
* doing won't lead to an inconsistent cache when invalidation is suspended.
*
* @since 2.7.0
*
* @global bool $_wp_suspend_cache_invalidation
*
* @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
* @return bool The current suspend setting.
*/
function wp_suspend_cache_invalidation( $suspend = true ) {
global $_wp_suspend_cache_invalidation;
$current_suspend = $_wp_suspend_cache_invalidation;
$_wp_suspend_cache_invalidation = $suspend;
return $current_suspend;
}
/**
* Determines whether a site is the main site of the current network.
*
* @since 3.0.0
* @since 4.9.0 The `$network_id` parameter was added.
*
* @param int $site_id Optional. Site ID to test. Defaults to current site.
* @param int $network_id Optional. Network ID of the network to check for.
* Defaults to current network.
* @return bool True if $site_id is the main site of the network, or if not
* running Multisite.
*/
function is_main_site( $site_id = null, $network_id = null ) {
if ( ! is_multisite() ) {
return true;
}
if ( ! $site_id ) {
$site_id = get_current_blog_id();
}
$site_id = (int) $site_id;
return get_main_site_id( $network_id ) === $site_id;
}
/**
* Gets the main site ID.
*
* @since 4.9.0
*
* @param int $network_id Optional. The ID of the network for which to get the main site.
* Defaults to the current network.
* @return int The ID of the main site.
*/
function get_main_site_id( $network_id = null ) {
if ( ! is_multisite() ) {
return get_current_blog_id();
}
$network = get_network( $network_id );
if ( ! $network ) {
return 0;
}
return $network->site_id;
}
/**
* Determines whether a network is the main network of the Multisite installation.
*
* @since 3.7.0
*
* @param int $network_id Optional. Network ID to test. Defaults to current network.
* @return bool True if $network_id is the main network, or if not running Multisite.
*/
function is_main_network( $network_id = null ) {
if ( ! is_multisite() ) {
return true;
}
if ( null === $network_id ) {
$network_id = get_current_network_id();
}
$network_id = (int) $network_id;
return ( get_main_network_id() === $network_id );
}
/**
* Gets the main network ID.
*
* @since 4.3.0
*
* @return int The ID of the main network.
*/
function get_main_network_id() {
if ( ! is_multisite() ) {
return 1;
}
$current_network = get_network();
if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
$main_network_id = PRIMARY_NETWORK_ID;
} elseif ( isset( $current_network->id ) && 1 === (int) $current_network->id ) {
// If the current network has an ID of 1, assume it is the main network.
$main_network_id = 1;
} else {
$_networks = get_networks(
array(
'fields' => 'ids',
'number' => 1,
)
);
$main_network_id = array_shift( $_networks );
}
/**
* Filters the main network ID.
*
* @since 4.3.0
*
* @param int $main_network_id The ID of the main network.
*/
return (int) apply_filters( 'get_main_network_id', $main_network_id );
}
/**
* Determines whether site meta is enabled.
*
* This function checks whether the 'blogmeta' database table exists. The result is saved as
* a setting for the main network, making it essentially a global setting. Subsequent requests
* will refer to this setting instead of running the query.
*
* @since 5.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return bool True if site meta is supported, false otherwise.
*/
function is_site_meta_supported() {
global $wpdb;
if ( ! is_multisite() ) {
return false;
}
$network_id = get_main_network_id();
$supported = get_network_option( $network_id, 'site_meta_supported', false );
if ( false === $supported ) {
$supported = $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->blogmeta}'" ) ? 1 : 0;
update_network_option( $network_id, 'site_meta_supported', $supported );
}
return (bool) $supported;
}
/**
* Modifies gmt_offset for smart timezone handling.
*
* Overrides the gmt_offset option if we have a timezone_string available.
*
* @since 2.8.0
*
* @return float|false Timezone GMT offset, false otherwise.
*/
function wp_timezone_override_offset() {
$timezone_string = get_option( 'timezone_string' );
if ( ! $timezone_string ) {
return false;
}
$timezone_object = timezone_open( $timezone_string );
$datetime_object = date_create();
if ( false === $timezone_object || false === $datetime_object ) {
return false;
}
return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
}
/**
* Sort-helper for timezones.
*
* @since 2.9.0
* @access private
*
* @param array $a
* @param array $b
* @return int
*/
function _wp_timezone_choice_usort_callback( $a, $b ) {
// Don't use translated versions of Etc.
if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
// Make the order of these more like the old dropdown.
if ( str_starts_with( $a['city'], 'GMT+' ) && str_starts_with( $b['city'], 'GMT+' ) ) {
return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
}
if ( 'UTC' === $a['city'] ) {
if ( str_starts_with( $b['city'], 'GMT+' ) ) {
return 1;
}
return -1;
}
if ( 'UTC' === $b['city'] ) {
if ( str_starts_with( $a['city'], 'GMT+' ) ) {
return -1;
}
return 1;
}
return strnatcasecmp( $a['city'], $b['city'] );
}
if ( $a['t_continent'] === $b['t_continent'] ) {
if ( $a['t_city'] === $b['t_city'] ) {
return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
}
return strnatcasecmp( $a['t_city'], $b['t_city'] );
} else {
// Force Etc to the bottom of the list.
if ( 'Etc' === $a['continent'] ) {
return 1;
}
if ( 'Etc' === $b['continent'] ) {
return -1;
}
return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
}
}
/**
* Gives a nicely-formatted list of timezone strings.
*
* @since 2.9.0
* @since 4.7.0 Added the `$locale` parameter.
*
* @param string $selected_zone Selected timezone.
* @param string $locale Optional. Locale to load the timezones in. Default current site locale.
* @return string
*/
function wp_timezone_choice( $selected_zone, $locale = null ) {
static $mo_loaded = false, $locale_loaded = null;
$continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific' );
// Load translations for continents and cities.
if ( ! $mo_loaded || $locale !== $locale_loaded ) {
$locale_loaded = $locale ? $locale : get_locale();
$mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
unload_textdomain( 'continents-cities', true );
load_textdomain( 'continents-cities', $mofile, $locale_loaded );
$mo_loaded = true;
}
$tz_identifiers = timezone_identifiers_list();
$zonen = array();
foreach ( $tz_identifiers as $zone ) {
$zone = explode( '/', $zone );
if ( ! in_array( $zone[0], $continents, true ) ) {
continue;
}
// This determines what gets set and translated - we don't translate Etc/* strings here, they are done later.
$exists = array(
0 => ( isset( $zone[0] ) && $zone[0] ),
1 => ( isset( $zone[1] ) && $zone[1] ),
2 => ( isset( $zone[2] ) && $zone[2] ),
);
$exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
$exists[4] = ( $exists[1] && $exists[3] );
$exists[5] = ( $exists[2] && $exists[3] );
// phpcs:disable WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText
$zonen[] = array(
'continent' => ( $exists[0] ? $zone[0] : '' ),
'city' => ( $exists[1] ? $zone[1] : '' ),
'subcity' => ( $exists[2] ? $zone[2] : '' ),
't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
't_city' => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
't_subcity' => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' ),
);
// phpcs:enable
}
usort( $zonen, '_wp_timezone_choice_usort_callback' );
$structure = array();
if ( empty( $selected_zone ) ) {
$structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
}
// If this is a deprecated, but valid, timezone string, display it at the top of the list as-is.
if ( in_array( $selected_zone, $tz_identifiers, true ) === false
&& in_array( $selected_zone, timezone_identifiers_list( DateTimeZone::ALL_WITH_BC ), true )
) {
$structure[] = '<option selected="selected" value="' . esc_attr( $selected_zone ) . '">' . esc_html( $selected_zone ) . '</option>';
}
foreach ( $zonen as $key => $zone ) {
// Build value in an array to join later.
$value = array( $zone['continent'] );
if ( empty( $zone['city'] ) ) {
// It's at the continent level (generally won't happen).
$display = $zone['t_continent'];
} else {
// It's inside a continent group.
// Continent optgroup.
if ( ! isset( $zonen[ $key - 1 ] ) || $zonen[ $key - 1 ]['continent'] !== $zone['continent'] ) {
$label = $zone['t_continent'];
$structure[] = '<optgroup label="' . esc_attr( $label ) . '">';
}
// Add the city to the value.
$value[] = $zone['city'];
$display = $zone['t_city'];
if ( ! empty( $zone['subcity'] ) ) {
// Add the subcity to the value.
$value[] = $zone['subcity'];
$display .= ' - ' . $zone['t_subcity'];
}
}
// Build the value.
$value = implode( '/', $value );
$selected = '';
if ( $value === $selected_zone ) {
$selected = 'selected="selected" ';
}
$structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . '</option>';
// Close continent optgroup.
if ( ! empty( $zone['city'] ) && ( ! isset( $zonen[ $key + 1 ] ) || ( isset( $zonen[ $key + 1 ] ) && $zonen[ $key + 1 ]['continent'] !== $zone['continent'] ) ) ) {
$structure[] = '</optgroup>';
}
}
// Do UTC.
$structure[] = '<optgroup label="' . esc_attr__( 'UTC' ) . '">';
$selected = '';
if ( 'UTC' === $selected_zone ) {
$selected = 'selected="selected" ';
}
$structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __( 'UTC' ) . '</option>';
$structure[] = '</optgroup>';
// Do manual UTC offsets.
$structure[] = '<optgroup label="' . esc_attr__( 'Manual Offsets' ) . '">';
$offset_range = array(
-12,
-11.5,
-11,
-10.5,
-10,
-9.5,
-9,
-8.5,
-8,
-7.5,
-7,
-6.5,
-6,
-5.5,
-5,
-4.5,
-4,
-3.5,
-3,
-2.5,
-2,
-1.5,
-1,
-0.5,
0,
0.5,
1,
1.5,
2,
2.5,
3,
3.5,
4,
4.5,
5,
5.5,
5.75,
6,
6.5,
7,
7.5,
8,
8.5,
8.75,
9,
9.5,
10,
10.5,
11,
11.5,
12,
12.75,
13,
13.75,
14,
);
foreach ( $offset_range as $offset ) {
if ( 0 <= $offset ) {
$offset_name = '+' . $offset;
} else {
$offset_name = (string) $offset;
}
$offset_value = $offset_name;
$offset_name = str_replace( array( '.25', '.5', '.75' ), array( ':15', ':30', ':45' ), $offset_name );
$offset_name = 'UTC' . $offset_name;
$offset_value = 'UTC' . $offset_value;
$selected = '';
if ( $offset_value === $selected_zone ) {
$selected = 'selected="selected" ';
}
$structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . '</option>';
}
$structure[] = '</optgroup>';
return implode( "\n", $structure );
}
/**
* Strips close comment and close php tags from file headers used by WP.
*
* @since 2.8.0
* @access private
*
* @see https://core.trac.wordpress.org/ticket/8497
*
* @param string $str Header comment to clean up.
* @return string
*/
function _cleanup_header_comment( $str ) {
return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) );
}
/**
* Permanently deletes comments or posts of any type that have held a status
* of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
*
* The default value of `EMPTY_TRASH_DAYS` is 30 (days).
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*/
function wp_scheduled_delete() {
global $wpdb;
$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
$posts_to_delete = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp ), ARRAY_A );
foreach ( (array) $posts_to_delete as $post ) {
$post_id = (int) $post['post_id'];
if ( ! $post_id ) {
continue;
}
$del_post = get_post( $post_id );
if ( ! $del_post || 'trash' !== $del_post->post_status ) {
delete_post_meta( $post_id, '_wp_trash_meta_status' );
delete_post_meta( $post_id, '_wp_trash_meta_time' );
} else {
wp_delete_post( $post_id );
}
}
$comments_to_delete = $wpdb->get_results( $wpdb->prepare( "SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp ), ARRAY_A );
foreach ( (array) $comments_to_delete as $comment ) {
$comment_id = (int) $comment['comment_id'];
if ( ! $comment_id ) {
continue;
}
$del_comment = get_comment( $comment_id );
if ( ! $del_comment || 'trash' !== $del_comment->comment_approved ) {
delete_comment_meta( $comment_id, '_wp_trash_meta_time' );
delete_comment_meta( $comment_id, '_wp_trash_meta_status' );
} else {
wp_delete_comment( $del_comment );
}
}
}
/**
* Retrieves metadata from a file.
*
* Searches for metadata in the first 8 KB of a file, such as a plugin or theme.
* Each piece of metadata must be on its own line. Fields can not span multiple
* lines, the value will get cut at the end of the first line.
*
* If the file data is not within that first 8 KB, then the author should correct
* their plugin file and move the data headers to the top.
*
* @link https://codex.wordpress.org/File_Header
*
* @since 2.9.0
*
* @param string $file Absolute path to the file.
* @param array $default_headers List of headers, in the format `array( 'HeaderKey' => 'Header Name' )`.
* @param string $context Optional. If specified adds filter hook {@see 'extra_$context_headers'}.
* Default empty string.
* @return string[] Array of file header values keyed by header name.
*/
function get_file_data( $file, $default_headers, $context = '' ) {
// Pull only the first 8 KB of the file in.
$file_data = file_get_contents( $file, false, null, 0, 8 * KB_IN_BYTES );
if ( false === $file_data ) {
$file_data = '';
}
// Make sure we catch CR-only line endings.
$file_data = str_replace( "\r", "\n", $file_data );
/**
* Filters extra file headers by context.
*
* The dynamic portion of the hook name, `$context`, refers to
* the context where extra headers might be loaded.
*
* @since 2.9.0
*
* @param array $extra_context_headers Empty array by default.
*/
$extra_headers = $context ? apply_filters( "extra_{$context}_headers", array() ) : array();
if ( $extra_headers ) {
$extra_headers = array_combine( $extra_headers, $extra_headers ); // Keys equal values.
$all_headers = array_merge( $extra_headers, (array) $default_headers );
} else {
$all_headers = $default_headers;
}
foreach ( $all_headers as $field => $regex ) {
if ( preg_match( '/^(?:[ \t]*<\?php)?[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] ) {
$all_headers[ $field ] = _cleanup_header_comment( $match[1] );
} else {
$all_headers[ $field ] = '';
}
}
return $all_headers;
}
/**
* Returns true.
*
* Useful for returning true to filters easily.
*
* @since 3.0.0
*
* @see __return_false()
*
* @return true True.
*/
function __return_true() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return true;
}
/**
* Returns false.
*
* Useful for returning false to filters easily.
*
* @since 3.0.0
*
* @see __return_true()
*
* @return false False.
*/
function __return_false() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return false;
}
/**
* Returns 0.
*
* Useful for returning 0 to filters easily.
*
* @since 3.0.0
*
* @return int 0.
*/
function __return_zero() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return 0;
}
/**
* Returns an empty array.
*
* Useful for returning an empty array to filters easily.
*
* @since 3.0.0
*
* @return array Empty array.
*/
function __return_empty_array() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return array();
}
/**
* Returns null.
*
* Useful for returning null to filters easily.
*
* @since 3.4.0
*
* @return null Null value.
*/
function __return_null() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return null;
}
/**
* Returns an empty string.
*
* Useful for returning an empty string to filters easily.
*
* @since 3.7.0
*
* @see __return_null()
*
* @return string Empty string.
*/
function __return_empty_string() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return '';
}
/**
* Sends a HTTP header to disable content type sniffing in browsers which support it.
*
* @since 3.0.0
*
* @see https://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
* @see https://src.chromium.org/viewvc/chrome?view=rev&revision=6985
*/
function send_nosniff_header() {
header( 'X-Content-Type-Options: nosniff' );
}
/**
* Returns a MySQL expression for selecting the week number based on the start_of_week option.
*
* @ignore
* @since 3.0.0
*
* @param string $column Database column.
* @return string SQL clause.
*/
function _wp_mysql_week( $column ) {
$start_of_week = (int) get_option( 'start_of_week' );
switch ( $start_of_week ) {
case 1:
return "WEEK( $column, 1 )";
case 2:
case 3:
case 4:
case 5:
case 6:
return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
case 0:
default:
return "WEEK( $column, 0 )";
}
}
/**
* Finds hierarchy loops using a callback function that maps object IDs to parent IDs.
*
* @since 3.1.0
* @access private
*
* @param callable $callback Function that accepts ( ID, $callback_args ) and outputs parent_ID.
* @param int $start The ID to start the loop check at.
* @param int $start_parent The parent_ID of $start to use instead of calling $callback( $start ).
* Use null to always use $callback.
* @param array $callback_args Optional. Additional arguments to send to $callback. Default empty array.
* @return array IDs of all members of loop.
*/
function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
$override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args );
if ( ! $arbitrary_loop_member ) {
return array();
}
return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
}
/**
* Uses the "The Tortoise and the Hare" algorithm to detect loops.
*
* For every step of the algorithm, the hare takes two steps and the tortoise one.
* If the hare ever laps the tortoise, there must be a loop.
*
* @since 3.1.0
* @access private
*
* @param callable $callback Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
* @param int $start The ID to start the loop check at.
* @param array $override Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
* Default empty array.
* @param array $callback_args Optional. Additional arguments to send to $callback. Default empty array.
* @param bool $_return_loop Optional. Return loop members or just detect presence of loop? Only set
* to true if you already know the given $start is part of a loop (otherwise
* the returned array might include branches). Default false.
* @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
* $_return_loop
*/
function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
$tortoise = $start;
$hare = $start;
$evanescent_hare = $start;
$return = array();
// Set evanescent_hare to one past hare. Increment hare two steps.
while (
$tortoise
&&
( $evanescent_hare = isset( $override[ $hare ] ) ? $override[ $hare ] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
&&
( $hare = isset( $override[ $evanescent_hare ] ) ? $override[ $evanescent_hare ] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
) {
if ( $_return_loop ) {
$return[ $tortoise ] = true;
$return[ $evanescent_hare ] = true;
$return[ $hare ] = true;
}
// Tortoise got lapped - must be a loop.
if ( $tortoise === $evanescent_hare || $tortoise === $hare ) {
return $_return_loop ? $return : $tortoise;
}
// Increment tortoise by one step.
$tortoise = isset( $override[ $tortoise ] ) ? $override[ $tortoise ] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
}
return false;
}
/**
* Sends a HTTP header to limit rendering of pages to same origin iframes.
*
* @since 3.1.3
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
*/
function send_frame_options_header() {
header( 'X-Frame-Options: SAMEORIGIN' );
}
/**
* Sends a referrer policy header so referrers are not sent externally from administration screens.
*
* @since 4.9.0
* @since 6.8.0 This function was moved from `wp-admin/includes/misc.php` to `wp-includes/functions.php`.
*/
function wp_admin_headers() {
$policy = 'strict-origin-when-cross-origin';
/**
* Filters the admin referrer policy header value.
*
* @since 4.9.0
* @since 4.9.5 The default value was changed to 'strict-origin-when-cross-origin'.
*
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
*
* @param string $policy The admin referrer policy header value. Default 'strict-origin-when-cross-origin'.
*/
$policy = apply_filters( 'admin_referrer_policy', $policy );
header( sprintf( 'Referrer-Policy: %s', $policy ) );
}
/**
* Retrieves a list of protocols to allow in HTML attributes.
*
* @since 3.3.0
* @since 4.3.0 Added 'webcal' to the protocols array.
* @since 4.7.0 Added 'urn' to the protocols array.
* @since 5.3.0 Added 'sms' to the protocols array.
* @since 5.6.0 Added 'irc6' and 'ircs' to the protocols array.
*
* @see wp_kses()
* @see esc_url()
*
* @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
* 'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed',
* 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
* This covers all common link protocols, except for 'javascript' which should not
* be allowed for untrusted users.
*/
function wp_allowed_protocols() {
static $protocols = array();
if ( empty( $protocols ) ) {
$protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
}
if ( ! did_action( 'wp_loaded' ) ) {
/**
* Filters the list of protocols allowed in HTML attributes.
*
* @since 3.0.0
*
* @param string[] $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
*/
$protocols = array_unique( (array) apply_filters( 'kses_allowed_protocols', $protocols ) );
}
return $protocols;
}
/**
* Returns a comma-separated string or array of functions that have been called to get
* to the current point in code.
*
* @since 3.4.0
*
* @see https://core.trac.wordpress.org/ticket/19589
*
* @param string $ignore_class Optional. A class to ignore all function calls within - useful
* when you want to just give info about the callee. Default null.
* @param int $skip_frames Optional. A number of stack frames to skip - useful for unwinding
* back to the source of the issue. Default 0.
* @param bool $pretty Optional. Whether you want a comma separated string instead of
* the raw array returned. Default true.
* @return string|array Either a string containing a reversed comma separated trace or an array
* of individual calls.
*/
function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
static $truncate_paths;
$trace = debug_backtrace( false );
$caller = array();
$check_class = ! is_null( $ignore_class );
++$skip_frames; // Skip this function.
if ( ! isset( $truncate_paths ) ) {
$truncate_paths = array(
wp_normalize_path( WP_CONTENT_DIR ),
wp_normalize_path( ABSPATH ),
);
}
foreach ( $trace as $call ) {
if ( $skip_frames > 0 ) {
--$skip_frames;
} elseif ( isset( $call['class'] ) ) {
if ( $check_class && $ignore_class === $call['class'] ) {
continue; // Filter out calls.
}
$caller[] = "{$call['class']}{$call['type']}{$call['function']}";
} else {
if ( in_array( $call['function'], array( 'do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array' ), true ) ) {
$caller[] = "{$call['function']}('{$call['args'][0]}')";
} elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ), true ) ) {
$filename = isset( $call['args'][0] ) ? $call['args'][0] : '';
$caller[] = $call['function'] . "('" . str_replace( $truncate_paths, '', wp_normalize_path( $filename ) ) . "')";
} else {
$caller[] = $call['function'];
}
}
}
if ( $pretty ) {
return implode( ', ', array_reverse( $caller ) );
} else {
return $caller;
}
}
/**
* Retrieves IDs that are not already present in the cache.
*
* @since 3.4.0
* @since 6.1.0 This function is no longer marked as "private".
*
* @param int[] $object_ids Array of IDs.
* @param string $cache_group The cache group to check against.
* @return int[] Array of IDs not present in the cache.
*/
function _get_non_cached_ids( $object_ids, $cache_group ) {
$object_ids = array_filter( $object_ids, '_validate_cache_id' );
$object_ids = array_unique( array_map( 'intval', $object_ids ), SORT_NUMERIC );
if ( empty( $object_ids ) ) {
return array();
}
$non_cached_ids = array();
$cache_values = wp_cache_get_multiple( $object_ids, $cache_group );
foreach ( $cache_values as $id => $value ) {
if ( false === $value ) {
$non_cached_ids[] = (int) $id;
}
}
return $non_cached_ids;
}
/**
* Checks whether the given cache ID is either an integer or an integer-like string.
*
* Both `16` and `"16"` are considered valid, other numeric types and numeric strings
* (`16.3` and `"16.3"`) are considered invalid.
*
* @since 6.3.0
*
* @param mixed $object_id The cache ID to validate.
* @return bool Whether the given $object_id is a valid cache ID.
*/
function _validate_cache_id( $object_id ) {
/*
* filter_var() could be used here, but the `filter` PHP extension
* is considered optional and may not be available.
*/
if ( is_int( $object_id )
|| ( is_string( $object_id ) && (string) (int) $object_id === $object_id ) ) {
return true;
}
/* translators: %s: The type of the given object ID. */
$message = sprintf( __( 'Object ID must be an integer, %s given.' ), gettype( $object_id ) );
_doing_it_wrong( '_get_non_cached_ids', $message, '6.3.0' );
return false;
}
/**
* Tests if the current device has the capability to upload files.
*
* @since 3.4.0
* @access private
*
* @return bool Whether the device is able to upload files.
*/
function _device_can_upload() {
if ( ! wp_is_mobile() ) {
return true;
}
$ua = $_SERVER['HTTP_USER_AGENT'];
if ( str_contains( $ua, 'iPhone' )
|| str_contains( $ua, 'iPad' )
|| str_contains( $ua, 'iPod' ) ) {
return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
}
return true;
}
/**
* Tests if a given path is a stream URL
*
* @since 3.5.0
*
* @param string $path The resource path or URL.
* @return bool True if the path is a stream URL.
*/
function wp_is_stream( $path ) {
$scheme_separator = strpos( $path, '://' );
if ( false === $scheme_separator ) {
// $path isn't a stream.
return false;
}
$stream = substr( $path, 0, $scheme_separator );
return in_array( $stream, stream_get_wrappers(), true );
}
/**
* Tests if the supplied date is valid for the Gregorian calendar.
*
* @since 3.5.0
*
* @link https://www.php.net/manual/en/function.checkdate.php
*
* @param int $month Month number.
* @param int $day Day number.
* @param int $year Year number.
* @param string $source_date The date to filter.
* @return bool True if valid date, false if not valid date.
*/
function wp_checkdate( $month, $day, $year, $source_date ) {
/**
* Filters whether the given date is valid for the Gregorian calendar.
*
* @since 3.5.0
*
* @param bool $checkdate Whether the given date is valid.
* @param string $source_date Date to check.
*/
return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
}
/**
* Loads the auth check for monitoring whether the user is still logged in.
*
* Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
*
* This is disabled for certain screens where a login screen could cause an
* inconvenient interruption. A filter called {@see 'wp_auth_check_load'} can be used
* for fine-grained control.
*
* @since 3.6.0
*/
function wp_auth_check_load() {
if ( ! is_admin() && ! is_user_logged_in() ) {
return;
}
if ( defined( 'IFRAME_REQUEST' ) ) {
return;
}
$screen = get_current_screen();
$hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
$show = ! in_array( $screen->id, $hidden, true );
/**
* Filters whether to load the authentication check.
*
* Returning a falsey value from the filter will effectively short-circuit
* loading the authentication check.
*
* @since 3.6.0
*
* @param bool $show Whether to load the authentication check.
* @param WP_Screen $screen The current screen object.
*/
if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
wp_enqueue_style( 'wp-auth-check' );
wp_enqueue_script( 'wp-auth-check' );
add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
}
}
/**
* Outputs the HTML that shows the wp-login dialog when the user is no longer logged in.
*
* @since 3.6.0
*/
function wp_auth_check_html() {
$login_url = wp_login_url();
$current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
$same_domain = str_starts_with( $login_url, $current_domain );
/**
* Filters whether the authentication check originated at the same domain.
*
* @since 3.6.0
*
* @param bool $same_domain Whether the authentication check originated at the same domain.
*/
$same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
$wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
?>
<div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
<div id="wp-auth-check-bg"></div>
<div id="wp-auth-check">
<button type="button" class="wp-auth-check-close button-link"><span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Close dialog' );
?>
</span></button>
<?php
if ( $same_domain ) {
$login_src = add_query_arg(
array(
'interim-login' => '1',
'wp_lang' => get_user_locale(),
),
$login_url
);
?>
<div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url( $login_src ); ?>"></div>
<?php
}
?>
<div class="wp-auth-fallback">
<p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e( 'Session expired' ); ?></b></p>
<p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e( 'Please log in again.' ); ?></a>
<?php _e( 'The login page will open in a new tab. After logging in you can close it and return to this page.' ); ?></p>
</div>
</div>
</div>
<?php
}
/**
* Checks whether a user is still logged in, for the heartbeat.
*
* Send a result that shows a log-in box if the user is no longer logged in,
* or if their cookie is within the grace period.
*
* @since 3.6.0
*
* @global int $login_grace_period
*
* @param array $response The Heartbeat response.
* @return array The Heartbeat response with 'wp-auth-check' value set.
*/
function wp_auth_check( $response ) {
$response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
return $response;
}
/**
* Returns RegEx body to liberally match an opening HTML tag.
*
* Matches an opening HTML tag that:
* 1. Is self-closing or
* 2. Has no body but has a closing tag of the same name or
* 3. Contains a body and a closing tag of the same name
*
* Note: this RegEx does not balance inner tags and does not attempt
* to produce valid HTML
*
* @since 3.6.0
*
* @param string $tag An HTML tag name. Example: 'video'.
* @return string Tag RegEx.
*/
function get_tag_regex( $tag ) {
if ( empty( $tag ) ) {
return '';
}
return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
}
/**
* Indicates if a given slug for a character set represents the UTF-8
* text encoding. If not provided, examines the current blog's charset.
*
* A charset is considered to represent UTF-8 if it is a case-insensitive
* match of "UTF-8" with or without the hyphen.
*
* Example:
*
* true === is_utf8_charset( 'UTF-8' );
* true === is_utf8_charset( 'utf8' );
* false === is_utf8_charset( 'latin1' );
* false === is_utf8_charset( 'UTF 8' );
*
* // Only strings match.
* false === is_utf8_charset( [ 'charset' => 'utf-8' ] );
*
* // Without a given charset, it depends on the site option "blog_charset".
* $is_utf8 = is_utf8_charset();
*
* @since 6.6.0
* @since 6.6.1 A wrapper for _is_utf8_charset
*
* @see _is_utf8_charset
*
* @param string|null $blog_charset Optional. Slug representing a text character encoding, or "charset".
* E.g. "UTF-8", "Windows-1252", "ISO-8859-1", "SJIS".
* Default value is to infer from "blog_charset" option.
* @return bool Whether the slug represents the UTF-8 encoding.
*/
function is_utf8_charset( $blog_charset = null ) {
return _is_utf8_charset( $blog_charset ?? get_option( 'blog_charset' ) );
}
/**
* Retrieves a canonical form of the provided charset appropriate for passing to PHP
* functions such as htmlspecialchars() and charset HTML attributes.
*
* @since 3.6.0
* @access private
*
* @see https://core.trac.wordpress.org/ticket/23688
*
* @param string $charset A charset name, e.g. "UTF-8", "Windows-1252", "SJIS".
* @return string The canonical form of the charset.
*/
function _canonical_charset( $charset ) {
if ( is_utf8_charset( $charset ) ) {
return 'UTF-8';
}
/*
* Normalize the ISO-8859-1 family of languages.
*
* This is not required for htmlspecialchars(), as it properly recognizes all of
* the input character sets that here are transformed into "ISO-8859-1".
*
* @todo Should this entire check be removed since it's not required for the stated purpose?
* @todo Should WordPress transform other potential charset equivalents, such as "latin1"?
*/
if (
( 0 === strcasecmp( 'iso-8859-1', $charset ) ) ||
( 0 === strcasecmp( 'iso8859-1', $charset ) )
) {
return 'ISO-8859-1';
}
return $charset;
}
/**
* Sets the mbstring internal encoding to a binary safe encoding when func_overload
* is enabled.
*
* When mbstring.func_overload is in use for multi-byte encodings, the results from
* strlen() and similar functions respect the utf8 characters, causing binary data
* to return incorrect lengths.
*
* This function overrides the mbstring encoding to a binary-safe encoding, and
* resets it to the users expected encoding afterwards through the
* `reset_mbstring_encoding` function.
*
* It is safe to recursively call this function, however each
* `mbstring_binary_safe_encoding()` call must be followed up with an equal number
* of `reset_mbstring_encoding()` calls.
*
* @since 3.7.0
*
* @see reset_mbstring_encoding()
*
* @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
* Default false.
*/
function mbstring_binary_safe_encoding( $reset = false ) {
static $encodings = array();
static $overloaded = null;
if ( is_null( $overloaded ) ) {
if ( function_exists( 'mb_internal_encoding' )
&& ( (int) ini_get( 'mbstring.func_overload' ) & 2 ) // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
) {
$overloaded = true;
} else {
$overloaded = false;
}
}
if ( false === $overloaded ) {
return;
}
if ( ! $reset ) {
$encoding = mb_internal_encoding();
array_push( $encodings, $encoding );
mb_internal_encoding( 'ISO-8859-1' );
}
if ( $reset && $encodings ) {
$encoding = array_pop( $encodings );
mb_internal_encoding( $encoding );
}
}
/**
* Resets the mbstring internal encoding to a users previously set encoding.
*
* @see mbstring_binary_safe_encoding()
*
* @since 3.7.0
*/
function reset_mbstring_encoding() {
mbstring_binary_safe_encoding( true );
}
/**
* Filters/validates a variable as a boolean.
*
* Alternative to `filter_var( $value, FILTER_VALIDATE_BOOLEAN )`.
*
* @since 4.0.0
*
* @param mixed $value Boolean value to validate.
* @return bool Whether the value is validated.
*/
function wp_validate_boolean( $value ) {
if ( is_bool( $value ) ) {
return $value;
}
if ( is_string( $value ) && 'false' === strtolower( $value ) ) {
return false;
}
return (bool) $value;
}
/**
* Deletes a file.
*
* @since 4.2.0
* @since 6.7.0 A return value was added.
*
* @param string $file The path to the file to delete.
* @return bool True on success, false on failure.
*/
function wp_delete_file( $file ) {
/**
* Filters the path of the file to delete.
*
* @since 2.1.0
*
* @param string $file Path to the file to delete.
*/
$delete = apply_filters( 'wp_delete_file', $file );
if ( ! empty( $delete ) ) {
return @unlink( $delete );
}
return false;
}
/**
* Deletes a file if its path is within the given directory.
*
* @since 4.9.7
*
* @param string $file Absolute path to the file to delete.
* @param string $directory Absolute path to a directory.
* @return bool True on success, false on failure.
*/
function wp_delete_file_from_directory( $file, $directory ) {
if ( wp_is_stream( $file ) ) {
$real_file = $file;
$real_directory = $directory;
} else {
$real_file = realpath( wp_normalize_path( $file ) );
$real_directory = realpath( wp_normalize_path( $directory ) );
}
if ( false !== $real_file ) {
$real_file = wp_normalize_path( $real_file );
}
if ( false !== $real_directory ) {
$real_directory = wp_normalize_path( $real_directory );
}
if ( false === $real_file || false === $real_directory || ! str_starts_with( $real_file, trailingslashit( $real_directory ) ) ) {
return false;
}
return wp_delete_file( $file );
}
/**
* Outputs a small JS snippet on preview tabs/windows to remove `window.name` when a user is navigating to another page.
*
* This prevents reusing the same tab for a preview when the user has navigated away.
*
* @since 4.3.0
*
* @global WP_Post $post Global post object.
*/
function wp_post_preview_js() {
global $post;
if ( ! is_preview() || empty( $post ) ) {
return;
}
// Has to match the window name used in post_submit_meta_box().
$name = 'wp-preview-' . (int) $post->ID;
ob_start();
?>
<script>
( function() {
var query = document.location.search;
if ( query && query.indexOf( 'preview=true' ) !== -1 ) {
window.name = '<?php echo $name; ?>';
}
if ( window.addEventListener ) {
window.addEventListener( 'pagehide', function() { window.name = ''; } );
}
}());
</script>
<?php
wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
}
/**
* Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601 (Y-m-d\TH:i:s).
*
* Explicitly strips timezones, as datetimes are not saved with any timezone
* information. Including any information on the offset could be misleading.
*
* Despite historical function name, the output does not conform to RFC3339 format,
* which must contain timezone.
*
* @since 4.4.0
*
* @param string $date_string Date string to parse and format.
* @return string Date formatted for ISO8601 without time zone.
*/
function mysql_to_rfc3339( $date_string ) {
return mysql2date( 'Y-m-d\TH:i:s', $date_string, false );
}
/**
* Attempts to raise the PHP memory limit for memory intensive processes.
*
* Only allows raising the existing limit and prevents lowering it.
*
* @since 4.6.0
*
* @param string $context Optional. Context in which the function is called. Accepts either 'admin',
* 'image', 'cron', or an arbitrary other context. If an arbitrary context is passed,
* the similarly arbitrary {@see '$context_memory_limit'} filter will be
* invoked. Default 'admin'.
* @return int|string|false The limit that was set or false on failure.
*/
function wp_raise_memory_limit( $context = 'admin' ) {
// Exit early if the limit cannot be changed.
if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
return false;
}
$current_limit = ini_get( 'memory_limit' );
$current_limit_int = wp_convert_hr_to_bytes( $current_limit );
if ( -1 === $current_limit_int ) {
return false;
}
$wp_max_limit = WP_MAX_MEMORY_LIMIT;
$wp_max_limit_int = wp_convert_hr_to_bytes( $wp_max_limit );
$filtered_limit = $wp_max_limit;
switch ( $context ) {
case 'admin':
/**
* Filters the maximum memory limit available for administration screens.
*
* This only applies to administrators, who may require more memory for tasks
* like updates. Memory limits when processing images (uploaded or edited by
* users of any role) are handled separately.
*
* The `WP_MAX_MEMORY_LIMIT` constant specifically defines the maximum memory
* limit available when in the administration back end. The default is 256M
* (256 megabytes of memory) or the original `memory_limit` php.ini value if
* this is higher.
*
* @since 3.0.0
* @since 4.6.0 The default now takes the original `memory_limit` into account.
*
* @param int|string $filtered_limit The maximum WordPress memory limit. Accepts an integer
* (bytes), or a shorthand string notation, such as '256M'.
*/
$filtered_limit = apply_filters( 'admin_memory_limit', $filtered_limit );
break;
case 'image':
/**
* Filters the memory limit allocated for image manipulation.
*
* @since 3.5.0
* @since 4.6.0 The default now takes the original `memory_limit` into account.
*
* @param int|string $filtered_limit Maximum memory limit to allocate for image processing.
* Default `WP_MAX_MEMORY_LIMIT` or the original
* php.ini `memory_limit`, whichever is higher.
* Accepts an integer (bytes), or a shorthand string
* notation, such as '256M'.
*/
$filtered_limit = apply_filters( 'image_memory_limit', $filtered_limit );
break;
case 'cron':
/**
* Filters the memory limit allocated for WP-Cron event processing.
*
* @since 6.3.0
*
* @param int|string $filtered_limit Maximum memory limit to allocate for WP-Cron.
* Default `WP_MAX_MEMORY_LIMIT` or the original
* php.ini `memory_limit`, whichever is higher.
* Accepts an integer (bytes), or a shorthand string
* notation, such as '256M'.
*/
$filtered_limit = apply_filters( 'cron_memory_limit', $filtered_limit );
break;
default:
/**
* Filters the memory limit allocated for an arbitrary context.
*
* The dynamic portion of the hook name, `$context`, refers to an arbitrary
* context passed on calling the function. This allows for plugins to define
* their own contexts for raising the memory limit.
*
* @since 4.6.0
*
* @param int|string $filtered_limit Maximum memory limit to allocate for this context.
* Default WP_MAX_MEMORY_LIMIT` or the original php.ini `memory_limit`,
* whichever is higher. Accepts an integer (bytes), or a
* shorthand string notation, such as '256M'.
*/
$filtered_limit = apply_filters( "{$context}_memory_limit", $filtered_limit );
break;
}
$filtered_limit_int = wp_convert_hr_to_bytes( $filtered_limit );
if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
if ( false !== ini_set( 'memory_limit', $filtered_limit ) ) {
return $filtered_limit;
} else {
return false;
}
} elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
if ( false !== ini_set( 'memory_limit', $wp_max_limit ) ) {
return $wp_max_limit;
} else {
return false;
}
}
return false;
}
/**
* Generates a random UUID (version 4).
*
* @since 4.7.0
*
* @return string UUID.
*/
function wp_generate_uuid4() {
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0x0fff ) | 0x4000,
mt_rand( 0, 0x3fff ) | 0x8000,
mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff )
);
}
/**
* Validates that a UUID is valid.
*
* @since 4.9.0
*
* @param mixed $uuid UUID to check.
* @param int $version Specify which version of UUID to check against. Default is none,
* to accept any UUID version. Otherwise, only version allowed is `4`.
* @return bool The string is a valid UUID or false on failure.
*/
function wp_is_uuid( $uuid, $version = null ) {
if ( ! is_string( $uuid ) ) {
return false;
}
if ( is_numeric( $version ) ) {
if ( 4 !== (int) $version ) {
_doing_it_wrong( __FUNCTION__, __( 'Only UUID V4 is supported at this time.' ), '4.9.0' );
return false;
}
$regex = '/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/';
} else {
$regex = '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/';
}
return (bool) preg_match( $regex, $uuid );
}
/**
* Gets unique ID.
*
* This is a PHP implementation of Underscore's uniqueId method. A static variable
* contains an integer that is incremented with each call. This number is returned
* with the optional prefix. As such the returned value is not universally unique,
* but it is unique across the life of the PHP process.
*
* @since 5.0.3
*
* @param string $prefix Prefix for the returned ID.
* @return string Unique ID.
*/
function wp_unique_id( $prefix = '' ) {
static $id_counter = 0;
return $prefix . (string) ++$id_counter;
}
/**
* Generates an incremental ID that is independent per each different prefix.
*
* It is similar to `wp_unique_id`, but each prefix has its own internal ID
* counter to make each prefix independent from each other. The ID starts at 1
* and increments on each call. The returned value is not universally unique,
* but it is unique across the life of the PHP process and it's stable per
* prefix.
*
* @since 6.4.0
*
* @param string $prefix Optional. Prefix for the returned ID. Default empty string.
* @return string Incremental ID per prefix.
*/
function wp_unique_prefixed_id( $prefix = '' ) {
static $id_counters = array();
if ( ! is_string( $prefix ) ) {
wp_trigger_error(
__FUNCTION__,
sprintf( 'The prefix must be a string. "%s" data type given.', gettype( $prefix ) )
);
$prefix = '';
}
if ( ! isset( $id_counters[ $prefix ] ) ) {
$id_counters[ $prefix ] = 0;
}
$id = ++$id_counters[ $prefix ];
return $prefix . (string) $id;
}
/**
* Gets last changed date for the specified cache group.
*
* @since 4.7.0
*
* @param string $group Where the cache contents are grouped.
* @return string UNIX timestamp with microseconds representing when the group was last changed.
*/
function wp_cache_get_last_changed( $group ) {
$last_changed = wp_cache_get( 'last_changed', $group );
if ( $last_changed ) {
return $last_changed;
}
return wp_cache_set_last_changed( $group );
}
/**
* Sets last changed date for the specified cache group to now.
*
* @since 6.3.0
*
* @param string $group Where the cache contents are grouped.
* @return string UNIX timestamp when the group was last changed.
*/
function wp_cache_set_last_changed( $group ) {
$previous_time = wp_cache_get( 'last_changed', $group );
$time = microtime();
wp_cache_set( 'last_changed', $time, $group );
/**
* Fires after a cache group `last_changed` time is updated.
* This may occur multiple times per page load and registered
* actions must be performant.
*
* @since 6.3.0
*
* @param string $group The cache group name.
* @param string $time The new last changed time (msec sec).
* @param string|false $previous_time The previous last changed time. False if not previously set.
*/
do_action( 'wp_cache_set_last_changed', $group, $time, $previous_time );
return $time;
}
/**
* Sends an email to the old site admin email address when the site admin email address changes.
*
* @since 4.9.0
*
* @param string $old_email The old site admin email address.
* @param string $new_email The new site admin email address.
* @param string $option_name The relevant database option name.
*/
function wp_site_admin_email_change_notification( $old_email, $new_email, $option_name ) {
$send = true;
// Don't send the notification to the default 'admin_email' value.
if ( 'you@example.com' === $old_email ) {
$send = false;
}
/**
* Filters whether to send the site admin email change notification email.
*
* @since 4.9.0
*
* @param bool $send Whether to send the email notification.
* @param string $old_email The old site admin email address.
* @param string $new_email The new site admin email address.
*/
$send = apply_filters( 'send_site_admin_email_change_email', $send, $old_email, $new_email );
if ( ! $send ) {
return;
}
/* translators: Do not translate OLD_EMAIL, NEW_EMAIL, SITENAME, SITEURL: those are placeholders. */
$email_change_text = __(
'Hi,
This notice confirms that the admin email address was changed on ###SITENAME###.
The new admin email address is ###NEW_EMAIL###.
This email has been sent to ###OLD_EMAIL###
Regards,
All at ###SITENAME###
###SITEURL###'
);
$email_change_email = array(
'to' => $old_email,
/* translators: Site admin email change notification email subject. %s: Site title. */
'subject' => __( '[%s] Admin Email Changed' ),
'message' => $email_change_text,
'headers' => '',
);
// Get site name.
$site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
/**
* Filters the contents of the email notification sent when the site admin email address is changed.
*
* @since 4.9.0
*
* @param array $email_change_email {
* Used to build wp_mail().
*
* @type string $to The intended recipient.
* @type string $subject The subject of the email.
* @type string $message The content of the email.
* The following strings have a special meaning and will get replaced dynamically:
* - ###OLD_EMAIL### The old site admin email address.
* - ###NEW_EMAIL### The new site admin email address.
* - ###SITENAME### The name of the site.
* - ###SITEURL### The URL to the site.
* @type string $headers Headers.
* }
* @param string $old_email The old site admin email address.
* @param string $new_email The new site admin email address.
*/
$email_change_email = apply_filters( 'site_admin_email_change_email', $email_change_email, $old_email, $new_email );
$email_change_email['message'] = str_replace( '###OLD_EMAIL###', $old_email, $email_change_email['message'] );
$email_change_email['message'] = str_replace( '###NEW_EMAIL###', $new_email, $email_change_email['message'] );
$email_change_email['message'] = str_replace( '###SITENAME###', $site_name, $email_change_email['message'] );
$email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] );
wp_mail(
$email_change_email['to'],
sprintf(
$email_change_email['subject'],
$site_name
),
$email_change_email['message'],
$email_change_email['headers']
);
}
/**
* Returns an anonymized IPv4 or IPv6 address.
*
* @since 4.9.6 Abstracted from `WP_Community_Events::get_unsafe_client_ip()`.
*
* @param string $ip_addr The IPv4 or IPv6 address to be anonymized.
* @param bool $ipv6_fallback Optional. Whether to return the original IPv6 address if the needed functions
* to anonymize it are not present. Default false, return `::` (unspecified address).
* @return string The anonymized IP address.
*/
function wp_privacy_anonymize_ip( $ip_addr, $ipv6_fallback = false ) {
if ( empty( $ip_addr ) ) {
return '0.0.0.0';
}
// Detect what kind of IP address this is.
$ip_prefix = '';
$is_ipv6 = substr_count( $ip_addr, ':' ) > 1;
$is_ipv4 = ( 3 === substr_count( $ip_addr, '.' ) );
if ( $is_ipv6 && $is_ipv4 ) {
// IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4.
$ip_prefix = '::ffff:';
$ip_addr = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $ip_addr );
$ip_addr = str_replace( ']', '', $ip_addr );
$is_ipv6 = false;
}
if ( $is_ipv6 ) {
// IPv6 addresses will always be enclosed in [] if there's a port.
$left_bracket = strpos( $ip_addr, '[' );
$right_bracket = strpos( $ip_addr, ']' );
$percent = strpos( $ip_addr, '%' );
$netmask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
// Strip the port (and [] from IPv6 addresses), if they exist.
if ( false !== $left_bracket && false !== $right_bracket ) {
$ip_addr = substr( $ip_addr, $left_bracket + 1, $right_bracket - $left_bracket - 1 );
} elseif ( false !== $left_bracket || false !== $right_bracket ) {
// The IP has one bracket, but not both, so it's malformed.
return '::';
}
// Strip the reachability scope.
if ( false !== $percent ) {
$ip_addr = substr( $ip_addr, 0, $percent );
}
// No invalid characters should be left.
if ( preg_match( '/[^0-9a-f:]/i', $ip_addr ) ) {
return '::';
}
// Partially anonymize the IP by reducing it to the corresponding network ID.
if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
$ip_addr = inet_ntop( inet_pton( $ip_addr ) & inet_pton( $netmask ) );
if ( false === $ip_addr ) {
return '::';
}
} elseif ( ! $ipv6_fallback ) {
return '::';
}
} elseif ( $is_ipv4 ) {
// Strip any port and partially anonymize the IP.
$last_octet_position = strrpos( $ip_addr, '.' );
$ip_addr = substr( $ip_addr, 0, $last_octet_position ) . '.0';
} else {
return '0.0.0.0';
}
// Restore the IPv6 prefix to compatibility mode addresses.
return $ip_prefix . $ip_addr;
}
/**
* Returns uniform "anonymous" data by type.
*
* @since 4.9.6
*
* @param string $type The type of data to be anonymized.
* @param string $data Optional. The data to be anonymized. Default empty string.
* @return string The anonymous data for the requested type.
*/
function wp_privacy_anonymize_data( $type, $data = '' ) {
switch ( $type ) {
case 'email':
$anonymous = 'deleted@site.invalid';
break;
case 'url':
$anonymous = 'https://site.invalid';
break;
case 'ip':
$anonymous = wp_privacy_anonymize_ip( $data );
break;
case 'date':
$anonymous = '0000-00-00 00:00:00';
break;
case 'text':
/* translators: Deleted text. */
$anonymous = __( '[deleted]' );
break;
case 'longtext':
/* translators: Deleted long text. */
$anonymous = __( 'This content was deleted by the author.' );
break;
default:
$anonymous = '';
break;
}
/**
* Filters the anonymous data for each type.
*
* @since 4.9.6
*
* @param string $anonymous Anonymized data.
* @param string $type Type of the data.
* @param string $data Original data.
*/
return apply_filters( 'wp_privacy_anonymize_data', $anonymous, $type, $data );
}
/**
* Returns the directory used to store personal data export files.
*
* @since 4.9.6
*
* @see wp_privacy_exports_url
*
* @return string Exports directory.
*/
function wp_privacy_exports_dir() {
$upload_dir = wp_upload_dir();
$exports_dir = trailingslashit( $upload_dir['basedir'] ) . 'wp-personal-data-exports/';
/**
* Filters the directory used to store personal data export files.
*
* @since 4.9.6
* @since 5.5.0 Exports now use relative paths, so changes to the directory
* via this filter should be reflected on the server.
*
* @param string $exports_dir Exports directory.
*/
return apply_filters( 'wp_privacy_exports_dir', $exports_dir );
}
/**
* Returns the URL of the directory used to store personal data export files.
*
* @since 4.9.6
*
* @see wp_privacy_exports_dir
*
* @return string Exports directory URL.
*/
function wp_privacy_exports_url() {
$upload_dir = wp_upload_dir();
$exports_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-personal-data-exports/';
/**
* Filters the URL of the directory used to store personal data export files.
*
* @since 4.9.6
* @since 5.5.0 Exports now use relative paths, so changes to the directory URL
* via this filter should be reflected on the server.
*
* @param string $exports_url Exports directory URL.
*/
return apply_filters( 'wp_privacy_exports_url', $exports_url );
}
/**
* Schedules a `WP_Cron` job to delete expired export files.
*
* @since 4.9.6
*/
function wp_schedule_delete_old_privacy_export_files() {
if ( wp_installing() ) {
return;
}
if ( ! wp_next_scheduled( 'wp_privacy_delete_old_export_files' ) ) {
wp_schedule_event( time(), 'hourly', 'wp_privacy_delete_old_export_files' );
}
}
/**
* Cleans up export files older than three days old.
*
* The export files are stored in `wp-content/uploads`, and are therefore publicly
* accessible. A CSPRN is appended to the filename to mitigate the risk of an
* unauthorized person downloading the file, but it is still possible. Deleting
* the file after the data subject has had a chance to delete it adds an additional
* layer of protection.
*
* @since 4.9.6
*/
function wp_privacy_delete_old_export_files() {
$exports_dir = wp_privacy_exports_dir();
if ( ! is_dir( $exports_dir ) ) {
return;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
$export_files = list_files( $exports_dir, 100, array( 'index.php' ) );
/**
* Filters the lifetime, in seconds, of a personal data export file.
*
* By default, the lifetime is 3 days. Once the file reaches that age, it will automatically
* be deleted by a cron job.
*
* @since 4.9.6
*
* @param int $expiration The expiration age of the export, in seconds.
*/
$expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS );
foreach ( (array) $export_files as $export_file ) {
$file_age_in_seconds = time() - filemtime( $export_file );
if ( $expiration < $file_age_in_seconds ) {
unlink( $export_file );
}
}
}
/**
* Gets the URL to learn more about updating the PHP version the site is running on.
*
* This URL can be overridden by specifying an environment variable `WP_UPDATE_PHP_URL` or by using the
* {@see 'wp_update_php_url'} filter. Providing an empty string is not allowed and will result in the
* default URL being used. Furthermore the page the URL links to should preferably be localized in the
* site language.
*
* @since 5.1.0
*
* @return string URL to learn more about updating PHP.
*/
function wp_get_update_php_url() {
$default_url = wp_get_default_update_php_url();
$update_url = $default_url;
if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
$update_url = getenv( 'WP_UPDATE_PHP_URL' );
}
/**
* Filters the URL to learn more about updating the PHP version the site is running on.
*
* Providing an empty string is not allowed and will result in the default URL being used. Furthermore
* the page the URL links to should preferably be localized in the site language.
*
* @since 5.1.0
*
* @param string $update_url URL to learn more about updating PHP.
*/
$update_url = apply_filters( 'wp_update_php_url', $update_url );
if ( empty( $update_url ) ) {
$update_url = $default_url;
}
return $update_url;
}
/**
* Gets the default URL to learn more about updating the PHP version the site is running on.
*
* Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_php_url()} when relying on the URL.
* This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
* default one.
*
* @since 5.1.0
* @access private
*
* @return string Default URL to learn more about updating PHP.
*/
function wp_get_default_update_php_url() {
return _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page' );
}
/**
* Prints the default annotation for the web host altering the "Update PHP" page URL.
*
* This function is to be used after {@see wp_get_update_php_url()} to display a consistent
* annotation if the web host has altered the default "Update PHP" page URL.
*
* @since 5.1.0
* @since 5.2.0 Added the `$before` and `$after` parameters.
* @since 6.4.0 Added the `$display` parameter.
*
* @param string $before Markup to output before the annotation. Default `<p class="description">`.
* @param string $after Markup to output after the annotation. Default `</p>`.
* @param bool $display Whether to echo or return the markup. Default `true` for echo.
*
* @return string|void
*/
function wp_update_php_annotation( $before = '<p class="description">', $after = '</p>', $display = true ) {
$annotation = wp_get_update_php_annotation();
if ( $annotation ) {
if ( $display ) {
echo $before . $annotation . $after;
} else {
return $before . $annotation . $after;
}
}
}
/**
* Returns the default annotation for the web hosting altering the "Update PHP" page URL.
*
* This function is to be used after {@see wp_get_update_php_url()} to return a consistent
* annotation if the web host has altered the default "Update PHP" page URL.
*
* @since 5.2.0
*
* @return string Update PHP page annotation. An empty string if no custom URLs are provided.
*/
function wp_get_update_php_annotation() {
$update_url = wp_get_update_php_url();
$default_url = wp_get_default_update_php_url();
if ( $update_url === $default_url ) {
return '';
}
$annotation = sprintf(
/* translators: %s: Default Update PHP page URL. */
__( 'This resource is provided by your web host, and is specific to your site. For more information, <a href="%s" target="_blank">see the official WordPress documentation</a>.' ),
esc_url( $default_url )
);
return $annotation;
}
/**
* Gets the URL for directly updating the PHP version the site is running on.
*
* A URL will only be returned if the `WP_DIRECT_UPDATE_PHP_URL` environment variable is specified or
* by using the {@see 'wp_direct_php_update_url'} filter. This allows hosts to send users directly to
* the page where they can update PHP to a newer version.
*
* @since 5.1.1
*
* @return string URL for directly updating PHP or empty string.
*/
function wp_get_direct_php_update_url() {
$direct_update_url = '';
if ( false !== getenv( 'WP_DIRECT_UPDATE_PHP_URL' ) ) {
$direct_update_url = getenv( 'WP_DIRECT_UPDATE_PHP_URL' );
}
/**
* Filters the URL for directly updating the PHP version the site is running on from the host.
*
* @since 5.1.1
*
* @param string $direct_update_url URL for directly updating PHP.
*/
$direct_update_url = apply_filters( 'wp_direct_php_update_url', $direct_update_url );
return $direct_update_url;
}
/**
* Displays a button directly linking to a PHP update process.
*
* This provides hosts with a way for users to be sent directly to their PHP update process.
*
* The button is only displayed if a URL is returned by `wp_get_direct_php_update_url()`.
*
* @since 5.1.1
*/
function wp_direct_php_update_button() {
$direct_update_url = wp_get_direct_php_update_url();
if ( empty( $direct_update_url ) ) {
return;
}
echo '<p class="button-container">';
printf(
'<a class="button button-primary" href="%1$s" target="_blank">%2$s<span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
esc_url( $direct_update_url ),
__( 'Update PHP' ),
/* translators: Hidden accessibility text. */
__( '(opens in a new tab)' )
);
echo '</p>';
}
/**
* Gets the URL to learn more about updating the site to use HTTPS.
*
* This URL can be overridden by specifying an environment variable `WP_UPDATE_HTTPS_URL` or by using the
* {@see 'wp_update_https_url'} filter. Providing an empty string is not allowed and will result in the
* default URL being used. Furthermore the page the URL links to should preferably be localized in the
* site language.
*
* @since 5.7.0
*
* @return string URL to learn more about updating to HTTPS.
*/
function wp_get_update_https_url() {
$default_url = wp_get_default_update_https_url();
$update_url = $default_url;
if ( false !== getenv( 'WP_UPDATE_HTTPS_URL' ) ) {
$update_url = getenv( 'WP_UPDATE_HTTPS_URL' );
}
/**
* Filters the URL to learn more about updating the HTTPS version the site is running on.
*
* Providing an empty string is not allowed and will result in the default URL being used. Furthermore
* the page the URL links to should preferably be localized in the site language.
*
* @since 5.7.0
*
* @param string $update_url URL to learn more about updating HTTPS.
*/
$update_url = apply_filters( 'wp_update_https_url', $update_url );
if ( empty( $update_url ) ) {
$update_url = $default_url;
}
return $update_url;
}
/**
* Gets the default URL to learn more about updating the site to use HTTPS.
*
* Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_https_url()} when relying on the URL.
* This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
* default one.
*
* @since 5.7.0
* @access private
*
* @return string Default URL to learn more about updating to HTTPS.
*/
function wp_get_default_update_https_url() {
/* translators: Documentation explaining HTTPS and why it should be used. */
return __( 'https://developer.wordpress.org/advanced-administration/security/https/' );
}
/**
* Gets the URL for directly updating the site to use HTTPS.
*
* A URL will only be returned if the `WP_DIRECT_UPDATE_HTTPS_URL` environment variable is specified or
* by using the {@see 'wp_direct_update_https_url'} filter. This allows hosts to send users directly to
* the page where they can update their site to use HTTPS.
*
* @since 5.7.0
*
* @return string URL for directly updating to HTTPS or empty string.
*/
function wp_get_direct_update_https_url() {
$direct_update_url = '';
if ( false !== getenv( 'WP_DIRECT_UPDATE_HTTPS_URL' ) ) {
$direct_update_url = getenv( 'WP_DIRECT_UPDATE_HTTPS_URL' );
}
/**
* Filters the URL for directly updating the PHP version the site is running on from the host.
*
* @since 5.7.0
*
* @param string $direct_update_url URL for directly updating PHP.
*/
$direct_update_url = apply_filters( 'wp_direct_update_https_url', $direct_update_url );
return $direct_update_url;
}
/**
* Gets the size of a directory.
*
* A helper function that is used primarily to check whether
* a blog has exceeded its allowed upload space.
*
* @since MU (3.0.0)
* @since 5.2.0 $max_execution_time parameter added.
*
* @param string $directory Full path of a directory.
* @param int $max_execution_time Maximum time to run before giving up. In seconds.
* The timeout is global and is measured from the moment WordPress started to load.
* @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
*/
function get_dirsize( $directory, $max_execution_time = null ) {
/*
* Exclude individual site directories from the total when checking the main site of a network,
* as they are subdirectories and should not be counted.
*/
if ( is_multisite() && is_main_site() ) {
$size = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
} else {
$size = recurse_dirsize( $directory, null, $max_execution_time );
}
return $size;
}
/**
* Gets the size of a directory recursively.
*
* Used by get_dirsize() to get a directory size when it contains other directories.
*
* @since MU (3.0.0)
* @since 4.3.0 The `$exclude` parameter was added.
* @since 5.2.0 The `$max_execution_time` parameter was added.
* @since 5.6.0 The `$directory_cache` parameter was added.
*
* @param string $directory Full path of a directory.
* @param string|string[] $exclude Optional. Full path of a subdirectory to exclude from the total,
* or array of paths. Expected without trailing slash(es).
* Default null.
* @param int $max_execution_time Optional. Maximum time to run before giving up. In seconds.
* The timeout is global and is measured from the moment
* WordPress started to load. Defaults to the value of
* `max_execution_time` PHP setting.
* @param array $directory_cache Optional. Array of cached directory paths.
* Defaults to the value of `dirsize_cache` transient.
* @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
*/
function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null, &$directory_cache = null ) {
$directory = untrailingslashit( $directory );
$save_cache = false;
if ( ! isset( $directory_cache ) ) {
$directory_cache = get_transient( 'dirsize_cache' );
$save_cache = true;
}
if ( isset( $directory_cache[ $directory ] ) && is_int( $directory_cache[ $directory ] ) ) {
return $directory_cache[ $directory ];
}
if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) ) {
return false;
}
if (
( is_string( $exclude ) && $directory === $exclude ) ||
( is_array( $exclude ) && in_array( $directory, $exclude, true ) )
) {
return false;
}
if ( null === $max_execution_time ) {
// Keep the previous behavior but attempt to prevent fatal errors from timeout if possible.
if ( function_exists( 'ini_get' ) ) {
$max_execution_time = ini_get( 'max_execution_time' );
} else {
// Disable...
$max_execution_time = 0;
}
// Leave 1 second "buffer" for other operations if $max_execution_time has reasonable value.
if ( $max_execution_time > 10 ) {
$max_execution_time -= 1;
}
}
/**
* Filters the amount of storage space used by one directory and all its children, in megabytes.
*
* Return the actual used space to short-circuit the recursive PHP file size calculation
* and use something else, like a CDN API or native operating system tools for better performance.
*
* @since 5.6.0
*
* @param int|false $space_used The amount of used space, in bytes. Default false.
* @param string $directory Full path of a directory.
* @param string|string[]|null $exclude Full path of a subdirectory to exclude from the total,
* or array of paths.
* @param int $max_execution_time Maximum time to run before giving up. In seconds.
* @param array $directory_cache Array of cached directory paths.
*/
$size = apply_filters( 'pre_recurse_dirsize', false, $directory, $exclude, $max_execution_time, $directory_cache );
if ( false === $size ) {
$size = 0;
$handle = opendir( $directory );
if ( $handle ) {
while ( ( $file = readdir( $handle ) ) !== false ) {
$path = $directory . '/' . $file;
if ( '.' !== $file && '..' !== $file ) {
if ( is_file( $path ) ) {
$size += filesize( $path );
} elseif ( is_dir( $path ) ) {
$handlesize = recurse_dirsize( $path, $exclude, $max_execution_time, $directory_cache );
if ( $handlesize > 0 ) {
$size += $handlesize;
}
}
if ( $max_execution_time > 0 &&
( microtime( true ) - WP_START_TIMESTAMP ) > $max_execution_time
) {
// Time exceeded. Give up instead of risking a fatal timeout.
$size = null;
break;
}
}
}
closedir( $handle );
}
}
if ( ! is_array( $directory_cache ) ) {
$directory_cache = array();
}
$directory_cache[ $directory ] = $size;
// Only write the transient on the top level call and not on recursive calls.
if ( $save_cache ) {
$expiration = ( wp_using_ext_object_cache() ) ? 0 : 10 * YEAR_IN_SECONDS;
set_transient( 'dirsize_cache', $directory_cache, $expiration );
}
return $size;
}
/**
* Cleans directory size cache used by recurse_dirsize().
*
* Removes the current directory and all parent directories from the `dirsize_cache` transient.
*
* @since 5.6.0
* @since 5.9.0 Added input validation with a notice for invalid input.
*
* @param string $path Full path of a directory or file.
*/
function clean_dirsize_cache( $path ) {
if ( ! is_string( $path ) || empty( $path ) ) {
wp_trigger_error(
'',
sprintf(
/* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */
__( '%1$s only accepts a non-empty path string, received %2$s.' ),
'<code>clean_dirsize_cache()</code>',
'<code>' . gettype( $path ) . '</code>'
)
);
return;
}
$directory_cache = get_transient( 'dirsize_cache' );
if ( empty( $directory_cache ) ) {
return;
}
$expiration = ( wp_using_ext_object_cache() ) ? 0 : 10 * YEAR_IN_SECONDS;
if (
! str_contains( $path, '/' ) &&
! str_contains( $path, '\\' )
) {
unset( $directory_cache[ $path ] );
set_transient( 'dirsize_cache', $directory_cache, $expiration );
return;
}
$last_path = null;
$path = untrailingslashit( $path );
unset( $directory_cache[ $path ] );
while (
$last_path !== $path &&
DIRECTORY_SEPARATOR !== $path &&
'.' !== $path &&
'..' !== $path
) {
$last_path = $path;
$path = dirname( $path );
unset( $directory_cache[ $path ] );
}
set_transient( 'dirsize_cache', $directory_cache, $expiration );
}
/**
* Returns the current WordPress version.
*
* Returns an unmodified value of `$wp_version`. Some plugins modify the global
* in an attempt to improve security through obscurity. This practice can cause
* errors in WordPress, so the ability to get an unmodified version is needed.
*
* @since 6.7.0
*
* @return string The current WordPress version.
*/
function wp_get_wp_version() {
static $wp_version;
if ( ! isset( $wp_version ) ) {
require ABSPATH . WPINC . '/version.php';
}
return $wp_version;
}
/**
* Checks compatibility with the current WordPress version.
*
* @since 5.2.0
*
* @global string $_wp_tests_wp_version The WordPress version string. Used only in Core tests.
*
* @param string $required Minimum required WordPress version.
* @return bool True if required version is compatible or empty, false if not.
*/
function is_wp_version_compatible( $required ) {
if (
defined( 'WP_RUN_CORE_TESTS' )
&& WP_RUN_CORE_TESTS
&& isset( $GLOBALS['_wp_tests_wp_version'] )
) {
$wp_version = $GLOBALS['_wp_tests_wp_version'];
} else {
$wp_version = wp_get_wp_version();
}
// Strip off any -alpha, -RC, -beta, -src suffixes.
list( $version ) = explode( '-', $wp_version );
if ( is_string( $required ) ) {
$trimmed = trim( $required );
if ( substr_count( $trimmed, '.' ) > 1 && str_ends_with( $trimmed, '.0' ) ) {
$required = substr( $trimmed, 0, -2 );
}
}
return empty( $required ) || version_compare( $version, $required, '>=' );
}
/**
* Checks compatibility with the current PHP version.
*
* @since 5.2.0
*
* @param string $required Minimum required PHP version.
* @return bool True if required version is compatible or empty, false if not.
*/
function is_php_version_compatible( $required ) {
return empty( $required ) || version_compare( PHP_VERSION, $required, '>=' );
}
/**
* Checks if two numbers are nearly the same.
*
* This is similar to using `round()` but the precision is more fine-grained.
*
* @since 5.3.0
*
* @param int|float $expected The expected value.
* @param int|float $actual The actual number.
* @param int|float $precision Optional. The allowed variation. Default 1.
* @return bool Whether the numbers match within the specified precision.
*/
function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
return abs( (float) $expected - (float) $actual ) <= $precision;
}
/**
* Creates and returns the markup for an admin notice.
*
* @since 6.4.0
*
* @param string $message The message.
* @param array $args {
* Optional. An array of arguments for the admin notice. Default empty array.
*
* @type string $type Optional. The type of admin notice.
* For example, 'error', 'success', 'warning', 'info'.
* Default empty string.
* @type bool $dismissible Optional. Whether the admin notice is dismissible. Default false.
* @type string $id Optional. The value of the admin notice's ID attribute. Default empty string.
* @type string[] $additional_classes Optional. A string array of class names. Default empty array.
* @type string[] $attributes Optional. Additional attributes for the notice div. Default empty array.
* @type bool $paragraph_wrap Optional. Whether to wrap the message in paragraph tags. Default true.
* }
* @return string The markup for an admin notice.
*/
function wp_get_admin_notice( $message, $args = array() ) {
$defaults = array(
'type' => '',
'dismissible' => false,
'id' => '',
'additional_classes' => array(),
'attributes' => array(),
'paragraph_wrap' => true,
);
$args = wp_parse_args( $args, $defaults );
/**
* Filters the arguments for an admin notice.
*
* @since 6.4.0
*
* @param array $args The arguments for the admin notice.
* @param string $message The message for the admin notice.
*/
$args = apply_filters( 'wp_admin_notice_args', $args, $message );
$id = '';
$classes = 'notice';
$attributes = '';
if ( is_string( $args['id'] ) ) {
$trimmed_id = trim( $args['id'] );
if ( '' !== $trimmed_id ) {
$id = 'id="' . $trimmed_id . '" ';
}
}
if ( is_string( $args['type'] ) ) {
$type = trim( $args['type'] );
if ( str_contains( $type, ' ' ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: The "type" key. */
__( 'The %s key must be a string without spaces.' ),
'<code>type</code>'
),
'6.4.0'
);
}
if ( '' !== $type ) {
$classes .= ' notice-' . $type;
}
}
if ( true === $args['dismissible'] ) {
$classes .= ' is-dismissible';
}
if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
$classes .= ' ' . implode( ' ', $args['additional_classes'] );
}
if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
$attributes = '';
foreach ( $args['attributes'] as $attr => $val ) {
if ( is_bool( $val ) ) {
$attributes .= $val ? ' ' . $attr : '';
} elseif ( is_int( $attr ) ) {
$attributes .= ' ' . esc_attr( trim( $val ) );
} elseif ( $val ) {
$attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
}
}
}
if ( false !== $args['paragraph_wrap'] ) {
$message = "<p>$message</p>";
}
$markup = sprintf( '<div %1$sclass="%2$s"%3$s>%4$s</div>', $id, $classes, $attributes, $message );
/**
* Filters the markup for an admin notice.
*
* @since 6.4.0
*
* @param string $markup The HTML markup for the admin notice.
* @param string $message The message for the admin notice.
* @param array $args The arguments for the admin notice.
*/
return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
}
/**
* Outputs an admin notice.
*
* @since 6.4.0
*
* @param string $message The message to output.
* @param array $args {
* Optional. An array of arguments for the admin notice. Default empty array.
*
* @type string $type Optional. The type of admin notice.
* For example, 'error', 'success', 'warning', 'info'.
* Default empty string.
* @type bool $dismissible Optional. Whether the admin notice is dismissible. Default false.
* @type string $id Optional. The value of the admin notice's ID attribute. Default empty string.
* @type string[] $additional_classes Optional. A string array of class names. Default empty array.
* @type string[] $attributes Optional. Additional attributes for the notice div. Default empty array.
* @type bool $paragraph_wrap Optional. Whether to wrap the message in paragraph tags. Default true.
* }
*/
function wp_admin_notice( $message, $args = array() ) {
/**
* Fires before an admin notice is output.
*
* @since 6.4.0
*
* @param string $message The message for the admin notice.
* @param array $args The arguments for the admin notice.
*/
do_action( 'wp_admin_notice', $message, $args );
echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
}
/**
* Checks if a mime type is for a HEIC/HEIF image.
*
* @since 6.7.0
*
* @param string $mime_type The mime type to check.
* @return bool Whether the mime type is for a HEIC/HEIF image.
*/
function wp_is_heic_image_mime_type( $mime_type ) {
$heic_mime_types = array(
'image/heic',
'image/heif',
'image/heic-sequence',
'image/heif-sequence',
);
return in_array( $mime_type, $heic_mime_types, true );
}
/**
* Returns a cryptographically secure hash of a message using a fast generic hash function.
*
* Use the wp_verify_fast_hash() function to verify the hash.
*
* This function does not salt the value prior to being hashed, therefore input to this function must originate from
* a random generator with sufficiently high entropy, preferably greater than 128 bits. This function is used internally
* in WordPress to hash security keys and application passwords which are generated with high entropy.
*
* Important:
*
* - This function must not be used for hashing user-generated passwords. Use wp_hash_password() for that.
* - This function must not be used for hashing other low-entropy input. Use wp_hash() for that.
*
* The BLAKE2b algorithm is used by Sodium to hash the message.
*
* @since 6.8.0
*
* @throws TypeError Thrown by Sodium if the message is not a string.
*
* @param string $message The message to hash.
* @return string The hash of the message.
*/
function wp_fast_hash(
#[\SensitiveParameter]
string $message
): string {
$hashed = sodium_crypto_generichash( $message, 'wp_fast_hash_6.8+', 30 );
return '$generic$' . sodium_bin2base64( $hashed, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING );
}
/**
* Checks whether a plaintext message matches the hashed value. Used to verify values hashed via wp_fast_hash().
*
* The function uses Sodium to hash the message and compare it to the hashed value. If the hash is not a generic hash,
* the hash is treated as a phpass portable hash in order to provide backward compatibility for passwords and security
* keys which were hashed using phpass prior to WordPress 6.8.0.
*
* @since 6.8.0
*
* @throws TypeError Thrown by Sodium if the message is not a string.
*
* @param string $message The plaintext message.
* @param string $hash Hash of the message to check against.
* @return bool Whether the message matches the hashed message.
*/
function wp_verify_fast_hash(
#[\SensitiveParameter]
string $message,
string $hash
): bool {
if ( ! str_starts_with( $hash, '$generic$' ) ) {
// Back-compat for old phpass hashes.
require_once ABSPATH . WPINC . '/class-phpass.php';
return ( new PasswordHash( 8, true ) )->CheckPassword( $message, $hash );
}
return hash_equals( $hash, wp_fast_hash( $message ) );
}
/**
* Generates a unique ID based on the structure and values of a given array.
*
* This function serializes the array into a JSON string and generates a hash
* that serves as a unique identifier. Optionally, a prefix can be added to
* the generated ID for context or categorization.
*
* @since 6.8.0
*
* @param array $data The input array to generate an ID from.
* @param string $prefix Optional. A prefix to prepend to the generated ID. Default ''.
*
* @return string The generated unique ID for the array.
*/
function wp_unique_id_from_values( array $data, string $prefix = '' ): string {
if ( empty( $data ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: parameter name. */
__( 'The %s argument must not be empty.' ),
'$data'
),
'6.8.0'
);
}
$serialized = wp_json_encode( $data );
$hash = substr( md5( $serialized ), 0, 8 );
return $prefix . $hash;
}<?php
/**
* Fonts functions.
*
* @package WordPress
* @subpackage Fonts
* @since 6.4.0
*/
/**
* Generates and prints font-face styles for given fonts or theme.json fonts.
*
* @since 6.4.0
*
* @param array[][] $fonts {
* Optional. The font-families and their font faces. Default empty array.
*
* @type array ...$0 {
* An indexed or associative (keyed by font-family) array of font variations for this font-family.
* Each font face has the following structure.
*
* @type array ...$0 {
* The font face properties.
*
* @type string $font-family The font-family property.
* @type string|string[] $src The URL(s) to each resource containing the font data.
* @type string $font-style Optional. The font-style property. Default 'normal'.
* @type string $font-weight Optional. The font-weight property. Default '400'.
* @type string $font-display Optional. The font-display property. Default 'fallback'.
* @type string $ascent-override Optional. The ascent-override property.
* @type string $descent-override Optional. The descent-override property.
* @type string $font-stretch Optional. The font-stretch property.
* @type string $font-variant Optional. The font-variant property.
* @type string $font-feature-settings Optional. The font-feature-settings property.
* @type string $font-variation-settings Optional. The font-variation-settings property.
* @type string $line-gap-override Optional. The line-gap-override property.
* @type string $size-adjust Optional. The size-adjust property.
* @type string $unicode-range Optional. The unicode-range property.
* }
* }
* }
*/
function wp_print_font_faces( $fonts = array() ) {
if ( empty( $fonts ) ) {
$fonts = WP_Font_Face_Resolver::get_fonts_from_theme_json();
}
if ( empty( $fonts ) ) {
return;
}
$wp_font_face = new WP_Font_Face();
$wp_font_face->generate_and_print( $fonts );
}
/**
* Generates and prints font-face styles defined the the theme style variations.
*
* @since 6.7.0
*
*/
function wp_print_font_faces_from_style_variations() {
$fonts = WP_Font_Face_Resolver::get_fonts_from_style_variations();
if ( empty( $fonts ) ) {
return;
}
wp_print_font_faces( $fonts );
}
/**
* Registers a new font collection in the font library.
*
* See {@link https://schemas.wp.org/trunk/font-collection.json} for the schema
* the font collection data must adhere to.
*
* @since 6.5.0
*
* @param string $slug Font collection slug. May only contain alphanumeric characters, dashes,
* and underscores. See sanitize_title().
* @param array $args {
* Font collection data.
*
* @type string $name Required. Name of the font collection shown in the Font Library.
* @type string $description Optional. A short descriptive summary of the font collection. Default empty.
* @type array|string $font_families Required. Array of font family definitions that are in the collection,
* or a string containing the path or URL to a JSON file containing the font collection.
* @type array $categories Optional. Array of categories, each with a name and slug, that are used by the
* fonts in the collection. Default empty.
* }
* @return WP_Font_Collection|WP_Error A font collection if it was registered
* successfully, or WP_Error object on failure.
*/
function wp_register_font_collection( string $slug, array $args ) {
return WP_Font_Library::get_instance()->register_font_collection( $slug, $args );
}
/**
* Unregisters a font collection from the Font Library.
*
* @since 6.5.0
*
* @param string $slug Font collection slug.
* @return bool True if the font collection was unregistered successfully, else false.
*/
function wp_unregister_font_collection( string $slug ) {
return WP_Font_Library::get_instance()->unregister_font_collection( $slug );
}
/**
* Retrieves font uploads directory information.
*
* Same as wp_font_dir() but "light weight" as it doesn't attempt to create the font uploads directory.
* Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
* when not uploading files.
*
* @since 6.5.0
*
* @see wp_font_dir()
*
* @return array See wp_font_dir() for description.
*/
function wp_get_font_dir() {
return wp_font_dir( false );
}
/**
* Returns an array containing the current fonts upload directory's path and URL.
*
* @since 6.5.0
*
* @param bool $create_dir Optional. Whether to check and create the font uploads directory. Default true.
* @return array {
* Array of information about the font upload directory.
*
* @type string $path Base directory and subdirectory or full path to the fonts upload directory.
* @type string $url Base URL and subdirectory or absolute URL to the fonts upload directory.
* @type string $subdir Subdirectory
* @type string $basedir Path without subdir.
* @type string $baseurl URL path without subdir.
* @type string|false $error False or error message.
* }
*/
function wp_font_dir( $create_dir = true ) {
/*
* Allow extenders to manipulate the font directory consistently.
*
* Ensures the upload_dir filter is fired both when calling this function
* directly and when the upload directory is filtered in the Font Face
* REST API endpoint.
*/
add_filter( 'upload_dir', '_wp_filter_font_directory' );
$font_dir = wp_upload_dir( null, $create_dir, false );
remove_filter( 'upload_dir', '_wp_filter_font_directory' );
return $font_dir;
}
/**
* A callback function for use in the {@see 'upload_dir'} filter.
*
* This function is intended for internal use only and should not be used by plugins and themes.
* Use wp_get_font_dir() instead.
*
* @since 6.5.0
* @access private
*
* @param string $font_dir The font directory.
* @return string The modified font directory.
*/
function _wp_filter_font_directory( $font_dir ) {
if ( doing_filter( 'font_dir' ) ) {
// Avoid an infinite loop.
return $font_dir;
}
$font_dir = array(
'path' => untrailingslashit( $font_dir['basedir'] ) . '/fonts',
'url' => untrailingslashit( $font_dir['baseurl'] ) . '/fonts',
'subdir' => '',
'basedir' => untrailingslashit( $font_dir['basedir'] ) . '/fonts',
'baseurl' => untrailingslashit( $font_dir['baseurl'] ) . '/fonts',
'error' => false,
);
/**
* Filters the fonts directory data.
*
* This filter allows developers to modify the fonts directory data.
*
* @since 6.5.0
*
* @param array $font_dir {
* Array of information about the font upload directory.
*
* @type string $path Base directory and subdirectory or full path to the fonts upload directory.
* @type string $url Base URL and subdirectory or absolute URL to the fonts upload directory.
* @type string $subdir Subdirectory
* @type string $basedir Path without subdir.
* @type string $baseurl URL path without subdir.
* @type string|false $error False or error message.
* }
*/
return apply_filters( 'font_dir', $font_dir );
}
/**
* Deletes child font faces when a font family is deleted.
*
* @access private
* @since 6.5.0
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
function _wp_after_delete_font_family( $post_id, $post ) {
if ( 'wp_font_family' !== $post->post_type ) {
return;
}
$font_faces = get_children(
array(
'post_parent' => $post_id,
'post_type' => 'wp_font_face',
)
);
foreach ( $font_faces as $font_face ) {
wp_delete_post( $font_face->ID, true );
}
}
/**
* Deletes associated font files when a font face is deleted.
*
* @access private
* @since 6.5.0
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
function _wp_before_delete_font_face( $post_id, $post ) {
if ( 'wp_font_face' !== $post->post_type ) {
return;
}
$font_files = get_post_meta( $post_id, '_wp_font_face_file', false );
$font_dir = untrailingslashit( wp_get_font_dir()['basedir'] );
foreach ( $font_files as $font_file ) {
wp_delete_file( $font_dir . '/' . $font_file );
}
}
/**
* Register the default font collections.
*
* @access private
* @since 6.5.0
*/
function _wp_register_default_font_collections() {
wp_register_font_collection(
'google-fonts',
array(
'name' => _x( 'Google Fonts', 'font collection name' ),
'description' => __( 'Install from Google Fonts. Fonts are copied to and served from your site.' ),
'font_families' => 'https://s.w.org/images/fonts/wp-6.7/collections/google-fonts-with-preview.json',
'categories' => array(
array(
'name' => _x( 'Sans Serif', 'font category' ),
'slug' => 'sans-serif',
),
array(
'name' => _x( 'Display', 'font category' ),
'slug' => 'display',
),
array(
'name' => _x( 'Serif', 'font category' ),
'slug' => 'serif',
),
array(
'name' => _x( 'Handwriting', 'font category' ),
'slug' => 'handwriting',
),
array(
'name' => _x( 'Monospace', 'font category' ),
'slug' => 'monospace',
),
),
)
);
}
<?php
/**
* HTTPS detection functions.
*
* @package WordPress
* @since 5.7.0
*/
/**
* Checks whether the website is using HTTPS.
*
* This is based on whether both the home and site URL are using HTTPS.
*
* @since 5.7.0
* @see wp_is_home_url_using_https()
* @see wp_is_site_url_using_https()
*
* @return bool True if using HTTPS, false otherwise.
*/
function wp_is_using_https() {
if ( ! wp_is_home_url_using_https() ) {
return false;
}
return wp_is_site_url_using_https();
}
/**
* Checks whether the current site URL is using HTTPS.
*
* @since 5.7.0
* @see home_url()
*
* @return bool True if using HTTPS, false otherwise.
*/
function wp_is_home_url_using_https() {
return 'https' === wp_parse_url( home_url(), PHP_URL_SCHEME );
}
/**
* Checks whether the current site's URL where WordPress is stored is using HTTPS.
*
* This checks the URL where WordPress application files (e.g. wp-blog-header.php or the wp-admin/ folder)
* are accessible.
*
* @since 5.7.0
* @see site_url()
*
* @return bool True if using HTTPS, false otherwise.
*/
function wp_is_site_url_using_https() {
/*
* Use direct option access for 'siteurl' and manually run the 'site_url'
* filter because `site_url()` will adjust the scheme based on what the
* current request is using.
*/
/** This filter is documented in wp-includes/link-template.php */
$site_url = apply_filters( 'site_url', get_option( 'siteurl' ), '', null, null );
return 'https' === wp_parse_url( $site_url, PHP_URL_SCHEME );
}
/**
* Checks whether HTTPS is supported for the server and domain.
*
* This function makes an HTTP request through `wp_get_https_detection_errors()`
* to check for HTTPS support. As this process can be resource-intensive,
* it should be used cautiously, especially in performance-sensitive environments,
* to avoid potential latency issues.
*
* @since 5.7.0
*
* @return bool True if HTTPS is supported, false otherwise.
*/
function wp_is_https_supported() {
$https_detection_errors = wp_get_https_detection_errors();
// If there are errors, HTTPS is not supported.
return empty( $https_detection_errors );
}
/**
* Runs a remote HTTPS request to detect whether HTTPS supported, and stores potential errors.
*
* This function checks for HTTPS support by making an HTTP request. As this process can be resource-intensive,
* it should be used cautiously, especially in performance-sensitive environments.
* It is called when HTTPS support needs to be validated.
*
* @since 6.4.0
* @access private
*
* @return array An array containing potential detection errors related to HTTPS, or an empty array if no errors are found.
*/
function wp_get_https_detection_errors() {
/**
* Short-circuits the process of detecting errors related to HTTPS support.
*
* Returning a `WP_Error` from the filter will effectively short-circuit the default logic of trying a remote
* request to the site over HTTPS, storing the errors array from the returned `WP_Error` instead.
*
* @since 6.4.0
*
* @param null|WP_Error $pre Error object to short-circuit detection,
* or null to continue with the default behavior.
*/
$support_errors = apply_filters( 'pre_wp_get_https_detection_errors', null );
if ( is_wp_error( $support_errors ) ) {
return $support_errors->errors;
}
$support_errors = new WP_Error();
$response = wp_remote_request(
home_url( '/', 'https' ),
array(
'headers' => array(
'Cache-Control' => 'no-cache',
),
'sslverify' => true,
)
);
if ( is_wp_error( $response ) ) {
$unverified_response = wp_remote_request(
home_url( '/', 'https' ),
array(
'headers' => array(
'Cache-Control' => 'no-cache',
),
'sslverify' => false,
)
);
if ( is_wp_error( $unverified_response ) ) {
$support_errors->add(
'https_request_failed',
__( 'HTTPS request failed.' )
);
} else {
$support_errors->add(
'ssl_verification_failed',
__( 'SSL verification failed.' )
);
}
$response = $unverified_response;
}
if ( ! is_wp_error( $response ) ) {
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
$support_errors->add( 'bad_response_code', wp_remote_retrieve_response_message( $response ) );
} elseif ( false === wp_is_local_html_output( wp_remote_retrieve_body( $response ) ) ) {
$support_errors->add( 'bad_response_source', __( 'It looks like the response did not come from this site.' ) );
}
}
return $support_errors->errors;
}
/**
* Checks whether a given HTML string is likely an output from this WordPress site.
*
* This function attempts to check for various common WordPress patterns whether they are included in the HTML string.
* Since any of these actions may be disabled through third-party code, this function may also return null to indicate
* that it was not possible to determine ownership.
*
* @since 5.7.0
* @access private
*
* @param string $html Full HTML output string, e.g. from a HTTP response.
* @return bool|null True/false for whether HTML was generated by this site, null if unable to determine.
*/
function wp_is_local_html_output( $html ) {
// 1. Check if HTML includes the site's Really Simple Discovery link.
if ( has_action( 'wp_head', 'rsd_link' ) ) {
$pattern = preg_replace( '#^https?:(?=//)#', '', esc_url( site_url( 'xmlrpc.php?rsd', 'rpc' ) ) ); // See rsd_link().
return str_contains( $html, $pattern );
}
// 2. Check if HTML includes the site's REST API link.
if ( has_action( 'wp_head', 'rest_output_link_wp_head' ) ) {
// Try both HTTPS and HTTP since the URL depends on context.
$pattern = preg_replace( '#^https?:(?=//)#', '', esc_url( get_rest_url() ) ); // See rest_output_link_wp_head().
return str_contains( $html, $pattern );
}
// Otherwise the result cannot be determined.
return null;
}
<?php
if (PHP_VERSION_ID < 70000) {
if (!is_callable('sodiumCompatAutoloader')) {
/**
* Sodium_Compat autoloader.
*
* @param string $class Class name to be autoloaded.
*
* @return bool Stop autoloading?
*/
function sodiumCompatAutoloader($class)
{
$namespace = 'ParagonIE_Sodium_';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = dirname(__FILE__) . '/src/' . str_replace('_', '/', $relative_class) . '.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
}
// Now that we have an autoloader, let's register it!
spl_autoload_register('sodiumCompatAutoloader');
}
} else {
require_once dirname(__FILE__) . '/autoload-php7.php';
}
/* Explicitly, always load the Compat class: */
if (!class_exists('ParagonIE_Sodium_Compat', false)) {
require_once dirname(__FILE__) . '/src/Compat.php';
}
if (!class_exists('SodiumException', false)) {
require_once dirname(__FILE__) . '/src/SodiumException.php';
}
if (PHP_VERSION_ID >= 50300) {
// Namespaces didn't exist before 5.3.0, so don't even try to use this
// unless PHP >= 5.3.0
require_once dirname(__FILE__) . '/lib/namespaced.php';
require_once dirname(__FILE__) . '/lib/sodium_compat.php';
if (!defined('SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES')) {
require_once dirname(__FILE__) . '/lib/php84compat_const.php';
}
} else {
require_once dirname(__FILE__) . '/src/PHP52/SplFixedArray.php';
}
if (PHP_VERSION_ID < 70200 || !extension_loaded('sodium')) {
if (PHP_VERSION_ID >= 50300 && !defined('SODIUM_CRYPTO_SCALARMULT_BYTES')) {
require_once dirname(__FILE__) . '/lib/php72compat_const.php';
}
if (PHP_VERSION_ID >= 70000) {
assert(class_exists('ParagonIE_Sodium_Compat'), 'Possible filesystem/autoloader bug?');
} else {
assert(class_exists('ParagonIE_Sodium_Compat'));
}
require_once(dirname(__FILE__) . '/lib/php72compat.php');
} elseif (!function_exists('sodium_crypto_stream_xchacha20_xor')) {
// Older versions of {PHP, ext/sodium} will not define these
require_once(dirname(__FILE__) . '/lib/php72compat.php');
}
if (PHP_VERSION_ID < 80400 || !extension_loaded('sodium')) {
require_once dirname(__FILE__) . '/lib/php84compat.php';
}
require_once(dirname(__FILE__) . '/lib/stream-xchacha20.php');
require_once(dirname(__FILE__) . '/lib/ristretto255.php');
<?php
if (class_exists('ParagonIE_Sodium_Core32_X25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_X25519
*/
abstract class ParagonIE_Sodium_Core32_X25519 extends ParagonIE_Sodium_Core32_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @param int $b
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_cswap(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g,
$b = 0
) {
$f0 = (int) $f[0]->toInt();
$f1 = (int) $f[1]->toInt();
$f2 = (int) $f[2]->toInt();
$f3 = (int) $f[3]->toInt();
$f4 = (int) $f[4]->toInt();
$f5 = (int) $f[5]->toInt();
$f6 = (int) $f[6]->toInt();
$f7 = (int) $f[7]->toInt();
$f8 = (int) $f[8]->toInt();
$f9 = (int) $f[9]->toInt();
$g0 = (int) $g[0]->toInt();
$g1 = (int) $g[1]->toInt();
$g2 = (int) $g[2]->toInt();
$g3 = (int) $g[3]->toInt();
$g4 = (int) $g[4]->toInt();
$g5 = (int) $g[5]->toInt();
$g6 = (int) $g[6]->toInt();
$g7 = (int) $g[7]->toInt();
$g8 = (int) $g[8]->toInt();
$g9 = (int) $g[9]->toInt();
$b = -$b;
/** @var int $x0 */
$x0 = ($f0 ^ $g0) & $b;
/** @var int $x1 */
$x1 = ($f1 ^ $g1) & $b;
/** @var int $x2 */
$x2 = ($f2 ^ $g2) & $b;
/** @var int $x3 */
$x3 = ($f3 ^ $g3) & $b;
/** @var int $x4 */
$x4 = ($f4 ^ $g4) & $b;
/** @var int $x5 */
$x5 = ($f5 ^ $g5) & $b;
/** @var int $x6 */
$x6 = ($f6 ^ $g6) & $b;
/** @var int $x7 */
$x7 = ($f7 ^ $g7) & $b;
/** @var int $x8 */
$x8 = ($f8 ^ $g8) & $b;
/** @var int $x9 */
$x9 = ($f9 ^ $g9) & $b;
$f[0] = ParagonIE_Sodium_Core32_Int32::fromInt($f0 ^ $x0);
$f[1] = ParagonIE_Sodium_Core32_Int32::fromInt($f1 ^ $x1);
$f[2] = ParagonIE_Sodium_Core32_Int32::fromInt($f2 ^ $x2);
$f[3] = ParagonIE_Sodium_Core32_Int32::fromInt($f3 ^ $x3);
$f[4] = ParagonIE_Sodium_Core32_Int32::fromInt($f4 ^ $x4);
$f[5] = ParagonIE_Sodium_Core32_Int32::fromInt($f5 ^ $x5);
$f[6] = ParagonIE_Sodium_Core32_Int32::fromInt($f6 ^ $x6);
$f[7] = ParagonIE_Sodium_Core32_Int32::fromInt($f7 ^ $x7);
$f[8] = ParagonIE_Sodium_Core32_Int32::fromInt($f8 ^ $x8);
$f[9] = ParagonIE_Sodium_Core32_Int32::fromInt($f9 ^ $x9);
$g[0] = ParagonIE_Sodium_Core32_Int32::fromInt($g0 ^ $x0);
$g[1] = ParagonIE_Sodium_Core32_Int32::fromInt($g1 ^ $x1);
$g[2] = ParagonIE_Sodium_Core32_Int32::fromInt($g2 ^ $x2);
$g[3] = ParagonIE_Sodium_Core32_Int32::fromInt($g3 ^ $x3);
$g[4] = ParagonIE_Sodium_Core32_Int32::fromInt($g4 ^ $x4);
$g[5] = ParagonIE_Sodium_Core32_Int32::fromInt($g5 ^ $x5);
$g[6] = ParagonIE_Sodium_Core32_Int32::fromInt($g6 ^ $x6);
$g[7] = ParagonIE_Sodium_Core32_Int32::fromInt($g7 ^ $x7);
$g[8] = ParagonIE_Sodium_Core32_Int32::fromInt($g8 ^ $x8);
$g[9] = ParagonIE_Sodium_Core32_Int32::fromInt($g9 ^ $x9);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_mul121666(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $h */
$h = array();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $f[$i]->toInt64()->mulInt(121666, 17);
}
$carry9 = $h[9]->addInt(1 << 24)->shiftRight(25);
$h[0] = $h[0]->addInt64($carry9->mulInt(19, 5));
$h[9] = $h[9]->subInt64($carry9->shiftLeft(25));
$carry1 = $h[1]->addInt(1 << 24)->shiftRight(25);
$h[2] = $h[2]->addInt64($carry1);
$h[1] = $h[1]->subInt64($carry1->shiftLeft(25));
$carry3 = $h[3]->addInt(1 << 24)->shiftRight(25);
$h[4] = $h[4]->addInt64($carry3);
$h[3] = $h[3]->subInt64($carry3->shiftLeft(25));
$carry5 = $h[5]->addInt(1 << 24)->shiftRight(25);
$h[6] = $h[6]->addInt64($carry5);
$h[5] = $h[5]->subInt64($carry5->shiftLeft(25));
$carry7 = $h[7]->addInt(1 << 24)->shiftRight(25);
$h[8] = $h[8]->addInt64($carry7);
$h[7] = $h[7]->subInt64($carry7->shiftLeft(25));
$carry0 = $h[0]->addInt(1 << 25)->shiftRight(26);
$h[1] = $h[1]->addInt64($carry0);
$h[0] = $h[0]->subInt64($carry0->shiftLeft(26));
$carry2 = $h[2]->addInt(1 << 25)->shiftRight(26);
$h[3] = $h[3]->addInt64($carry2);
$h[2] = $h[2]->subInt64($carry2->shiftLeft(26));
$carry4 = $h[4]->addInt(1 << 25)->shiftRight(26);
$h[5] = $h[5]->addInt64($carry4);
$h[4] = $h[4]->subInt64($carry4->shiftLeft(26));
$carry6 = $h[6]->addInt(1 << 25)->shiftRight(26);
$h[7] = $h[7]->addInt64($carry6);
$h[6] = $h[6]->subInt64($carry6->shiftLeft(26));
$carry8 = $h[8]->addInt(1 << 25)->shiftRight(26);
$h[9] = $h[9]->addInt64($carry8);
$h[8] = $h[8]->subInt64($carry8->shiftLeft(26));
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $h[$i]->toInt32();
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h2 */
$h2 = $h;
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h2);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10($n, $p)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
# fe_frombytes(x1,p);
$x1 = self::fe_frombytes($p);
# fe_1(x2);
$x2 = self::fe_1();
# fe_0(z2);
$z2 = self::fe_0();
# fe_copy(x3,x1);
$x3 = self::fe_copy($x1);
# fe_1(z3);
$z3 = self::fe_1();
# swap = 0;
/** @var int $swap */
$swap = 0;
# for (pos = 254;pos >= 0;--pos) {
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
/** @var int $b */
$b = self::chrToInt(
$e[(int) floor($pos / 8)]
) >> ($pos & 7);
# b &= 1;
$b &= 1;
# swap ^= b;
$swap ^= $b;
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# swap = b;
/** @var int $swap */
$swap = $b;
# fe_sub(tmp0,x3,z3);
$tmp0 = self::fe_sub($x3, $z3);
# fe_sub(tmp1,x2,z2);
$tmp1 = self::fe_sub($x2, $z2);
# fe_add(x2,x2,z2);
$x2 = self::fe_add($x2, $z2);
# fe_add(z2,x3,z3);
$z2 = self::fe_add($x3, $z3);
# fe_mul(z3,tmp0,x2);
$z3 = self::fe_mul($tmp0, $x2);
# fe_mul(z2,z2,tmp1);
$z2 = self::fe_mul($z2, $tmp1);
# fe_sq(tmp0,tmp1);
$tmp0 = self::fe_sq($tmp1);
# fe_sq(tmp1,x2);
$tmp1 = self::fe_sq($x2);
# fe_add(x3,z3,z2);
$x3 = self::fe_add($z3, $z2);
# fe_sub(z2,z3,z2);
$z2 = self::fe_sub($z3, $z2);
# fe_mul(x2,tmp1,tmp0);
$x2 = self::fe_mul($tmp1, $tmp0);
# fe_sub(tmp1,tmp1,tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
# fe_sq(z2,z2);
$z2 = self::fe_sq($z2);
# fe_mul121666(z3,tmp1);
$z3 = self::fe_mul121666($tmp1);
# fe_sq(x3,x3);
$x3 = self::fe_sq($x3);
# fe_add(tmp0,tmp0,z3);
$tmp0 = self::fe_add($tmp0, $z3);
# fe_mul(z3,x1,z2);
$z3 = self::fe_mul($x1, $z2);
# fe_mul(z2,tmp1,tmp0);
$z2 = self::fe_mul($tmp1, $tmp0);
}
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# fe_invert(z2,z2);
$z2 = self::fe_invert($z2);
# fe_mul(x2,x2,z2);
$x2 = self::fe_mul($x2, $z2);
# fe_tobytes(q,x2);
return (string) self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function edwards_to_montgomery(
ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY,
ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ
) {
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base($n)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
$A = self::ge_scalarmult_base($e);
if (
!($A->Y instanceof ParagonIE_Sodium_Core32_Curve25519_Fe)
||
!($A->Z instanceof ParagonIE_Sodium_Core32_Curve25519_Fe)
) {
throw new TypeError('Null points encountered');
}
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Ed25519', false)) {
return;
}
if (!class_exists('ParagonIE_Sodium_Core32_Curve25519')) {
require_once dirname(__FILE__) . '/Curve25519.php';
}
/**
* Class ParagonIE_Sodium_Core32_Ed25519
*/
abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair()
{
$seed = random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(&$pk, &$sk, $seed)
{
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new RangeException('crypto_sign keypair seed must be 32 bytes long');
}
/** @var string $pk */
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function publickey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey($sk)
{
/** @var string $sk */
$sk = hash('sha512', self::substr($sk, 0, 32), true);
$sk[0] = self::intToChr(
self::chrToInt($sk[0]) & 248
);
$sk[31] = self::intToChr(
(self::chrToInt($sk[31]) & 63) | 64
);
return self::sk_to_pk($sk);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519($pk)
{
if (self::small_order($pk)) {
throw new SodiumException('Public key is on a small order');
}
$A = self::ge_frombytes_negate_vartime($pk);
$p1 = self::ge_mul_l($A);
if (!self::fe_isnonzero($p1->X)) {
throw new SodiumException('Unexpected zero result');
}
# fe_1(one_minus_y);
# fe_sub(one_minus_y, one_minus_y, A.Y);
# fe_invert(one_minus_y, one_minus_y);
$one_minux_y = self::fe_invert(
self::fe_sub(
self::fe_1(),
$A->Y
)
);
# fe_1(x);
# fe_add(x, x, A.Y);
# fe_mul(x, x, one_minus_y);
$x = self::fe_mul(
self::fe_add(self::fe_1(), $A->Y),
$one_minux_y
);
# fe_tobytes(curve25519_pk, x);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk($sk)
{
return self::ge_p3_tobytes(
self::ge_scalarmult_base(
self::substr($sk, 0, 32)
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
/** @var string $signature */
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($message, $pk)
{
/** @var string $signature */
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress PossiblyInvalidArgument
*/
public static function sign_detached($message, $sk)
{
# crypto_hash_sha512(az, sk, 32);
$az = hash('sha512', self::substr($sk, 0, 32), true);
# az[0] &= 248;
# az[31] &= 63;
# az[31] |= 64;
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, az + 32, 32);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, nonce);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($az, 32, 32));
self::hash_update($hs, $message);
$nonceHash = hash_final($hs, true);
# memmove(sig + 32, sk + 32, 32);
$pk = self::substr($sk, 32, 32);
# sc_reduce(nonce);
# ge_scalarmult_base(&R, nonce);
# ge_p3_tobytes(sig, &R);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
$sig = self::ge_p3_tobytes(
self::ge_scalarmult_base($nonce)
);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, sig, 64);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, hram);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($sig, 0, 32));
self::hash_update($hs, self::substr($pk, 0, 32));
self::hash_update($hs, $message);
$hramHash = hash_final($hs, true);
# sc_reduce(hram);
# sc_muladd(sig + 32, hram, az, nonce);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached($sig, $message, $pk)
{
if (self::strlen($sig) < 64) {
throw new SodiumException('Signature is too short');
}
if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new SodiumException('S < L - Invalid signature');
}
if (self::small_order($sig)) {
throw new SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
$A = self::ge_frombytes_negate_vartime($pk);
/** @var string $hDigest */
$hDigest = hash(
'sha512',
self::substr($sig, 0, 32) .
self::substr($pk, 0, 32) .
$message,
true
);
/** @var string $h */
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
$R = self::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L($S)
{
if (self::strlen($S) < 32) {
throw new SodiumException('Signature must be 32 bytes');
}
static $L = array(
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
);
/** @var array<int, int> $L */
$c = 0;
$n = 1;
$i = 32;
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= (
(($x - $L[$i]) >> 8) & $n
);
$n &= (
(($x ^ $L[$i]) - 1) >> 8
);
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order($R)
{
static $blocklist = array(
/* 0 (order 4) */
array(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 1 (order 1) */
array(
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(
0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05
),
/* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(
0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a
),
/* p-1 (order 2) */
array(
0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85
),
/* p (order 4) */
array(
0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa
),
/* p+1 (order 1) */
array(
0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* 2p-1 (order 2) */
array(
0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p (order 4) */
array(
0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p+1 (order 1) */
array(
0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
)
);
/** @var array<int, array<int, int>> $blocklist */
$countBlocklist = count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j];
}
if ($c === 0) {
return true;
}
}
return false;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Poly1305', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305
*/
abstract class ParagonIE_Sodium_Core32_Poly1305 extends ParagonIE_Sodium_Core32_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth($m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
self::substr($key, 0, 32)
);
return $state
->update($m)
->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify($mac, $m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
self::substr($key, 0, 32)
);
$calc = $state
->update($m)
->finish();
return self::verify_16($calc, $mac);
}
}
<?php
/**
* Class ParagonIE_Sodium_Core32_SecretStream_State
*/
class ParagonIE_Sodium_Core32_SecretStream_State
{
/** @var string $key */
protected $key;
/** @var int $counter */
protected $counter;
/** @var string $nonce */
protected $nonce;
/** @var string $_pad */
protected $_pad;
/**
* ParagonIE_Sodium_Core32_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct($key, $nonce = null)
{
$this->key = $key;
$this->counter = 1;
if (is_null($nonce)) {
$nonce = str_repeat("\0", 12);
}
$this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);;
$this->_pad = str_repeat("\0", 4);
}
/**
* @return self
*/
public function counterReset()
{
$this->counter = 1;
$this->_pad = str_repeat("\0", 4);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return string
*/
public function getCounter()
{
return ParagonIE_Sodium_Core32_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce()
{
if (!is_string($this->nonce)) {
$this->nonce = str_repeat("\0", 12);
}
if (ParagonIE_Sodium_Core32_Util::strlen($this->nonce) !== 12) {
$this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT);
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce()
{
return $this->getCounter() .
ParagonIE_Sodium_Core32_Util::substr($this->getNonce(), 0, 8);
}
/**
* @return self
*/
public function incrementCounter()
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey()
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey($newKeyAndNonce)
{
$this->key = ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 0, 32);
$this->nonce = str_pad(
ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 32),
12,
"\0",
STR_PAD_RIGHT
);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce($str)
{
$this->nonce = ParagonIE_Sodium_Core32_Util::xorStrings(
$this->getNonce(),
str_pad(
ParagonIE_Sodium_Core32_Util::substr($str, 0, 8),
12,
"\0",
STR_PAD_RIGHT
)
);
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString($string)
{
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
ParagonIE_Sodium_Core32_Util::substr($string, 0, 32)
);
$state->counter = ParagonIE_Sodium_Core32_Util::load_4(
ParagonIE_Sodium_Core32_Util::substr($string, 32, 4)
);
$state->nonce = ParagonIE_Sodium_Core32_Util::substr($string, 36, 12);
$state->_pad = ParagonIE_Sodium_Core32_Util::substr($string, 48, 8);
return $state;
}
/**
* @return string
*/
public function toString()
{
return $this->key .
$this->getCounter() .
$this->nonce .
$this->_pad;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
public static $iv;
/**
* @var array<int, array<int, int>>
*/
public static $sigma = array(
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4),
array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8),
array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13),
array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9),
array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11),
array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10),
array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5),
array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0),
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3)
);
const BLOCKBYTES = 128;
const OUTBYTES = 64;
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function new64($high, $low)
{
return ParagonIE_Sodium_Core32_Int64::fromInts($low, $high);
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
protected static function to64($num)
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @return ParagonIE_Sodium_Core32_Int64
*/
protected static function add64($x, $y)
{
return $x->addInt64($y);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @param ParagonIE_Sodium_Core32_Int64 $z
* @return ParagonIE_Sodium_Core32_Int64
*/
public static function add364($x, $y, $z)
{
return $x->addInt64($y)->addInt64($z);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @return ParagonIE_Sodium_Core32_Int64
* @throws TypeError
*/
public static function xor64(ParagonIE_Sodium_Core32_Int64 $x, ParagonIE_Sodium_Core32_Int64 $y)
{
return $x->xorInt64($y);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function rotr64(ParagonIE_Sodium_Core32_Int64 $x, $c)
{
return $x->rotateRight($c);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function load64($x, $i)
{
/** @var int $l */
$l = (int) ($x[$i])
| ((int) ($x[$i+1]) << 8)
| ((int) ($x[$i+2]) << 16)
| ((int) ($x[$i+3]) << 24);
/** @var int $h */
$h = (int) ($x[$i+4])
| ((int) ($x[$i+5]) << 8)
| ((int) ($x[$i+6]) << 16)
| ((int) ($x[$i+7]) << 24);
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param ParagonIE_Sodium_Core32_Int64 $u
* @return void
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function store64(SplFixedArray $x, $i, ParagonIE_Sodium_Core32_Int64 $u)
{
$v = clone $u;
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
$k = 3 - ($j >> 1);
$x[$i] = $v->limbs[$k] & 0xff;
if (++$i > $maxLength) {
return;
}
$v->limbs[$k] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
* @throws SodiumException
* @throws TypeError
*/
public static function pseudoConstructor()
{
static $called = false;
if ($called) {
return;
}
self::$iv = new SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @throws SodiumException
* @throws TypeError
*/
protected static function context()
{
$ctx = new SplFixedArray(6);
$ctx[0] = new SplFixedArray(8); // h
$ctx[1] = new SplFixedArray(2); // t
$ctx[2] = new SplFixedArray(2); // f
$ctx[3] = new SplFixedArray(256); // buf
$ctx[4] = 0; // buflen
$ctx[5] = 0; // last_node (uint8_t)
for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedAssignment
*/
protected static function compress(SplFixedArray $ctx, SplFixedArray $buf)
{
$m = new SplFixedArray(16);
$v = new SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[ 8] = self::$iv[0];
$v[ 9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i], self::xor64($v[$i], $v[$i+8])
);
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v, SplFixedArray $m)
{
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function increment_counter($ctx, $inc)
{
if ($inc < 0) {
throw new SodiumException('Increasing by a negative number makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (!($ctx[1][0] instanceof ParagonIE_Sodium_Core32_Int64)) {
throw new TypeError('Not an int64');
}
/** @var ParagonIE_Sodium_Core32_Int64 $c*/
$c = $ctx[1][0];
if ($c->isLessThanInt($inc)) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedOperand
*/
public static function update(SplFixedArray $ctx, SplFixedArray $p, $plen)
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedOperand
*/
public static function finish(SplFixedArray $ctx, SplFixedArray $out)
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new SodiumException('Failed to assert that buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
/** @var int $i */
$ctx[3][$i + $ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedMethodCall
*/
public static function init(
$key = null,
$outlen = 64,
$salt = null,
$personal = null
) {
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (count($key) > 64) {
throw new SodiumException('Invalid key size');
}
$klen = count($key);
}
if ($outlen > 64) {
throw new SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen; // digest_length
$p[1] = $klen; // key_length
$p[2] = 1; // fanout
$p[3] = 1; // depth
if ($salt instanceof SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}
$ctx[0][0] = self::xor64(
$ctx[0][0],
self::load64($p, 0)
);
if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i],
self::load64($p, $i << 3)
);
}
}
if ($klen > 0 && $key instanceof SplFixedArray) {
$block = new SplFixedArray(128);
for ($i = 128; $i--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
* @psalm-suppress MixedArgumentTypeCoercion
*/
public static function stringToSplFixedArray($str = '')
{
$values = unpack('C*', $str);
return SplFixedArray::fromArray(array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
*/
public static function SplFixedArrayToString(SplFixedArray $a)
{
/**
* @var array<int, string|int>
*/
$arr = $a->toArray();
$c = $a->count();
array_unshift($arr, str_repeat('C', $c));
return (string) (call_user_func_array('pack', $arr));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedMethodCall
*/
public static function contextToString(SplFixedArray $ctx)
{
$str = '';
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
if (!($ctxA[$i] instanceof ParagonIE_Sodium_Core32_Int64)) {
throw new TypeError('Not an instance of Int64');
}
/** @var ParagonIE_Sodium_Core32_Int64 $ctxAi */
$ctxAi = $ctxA[$i];
$str .= $ctxAi->toReverseString();
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */
$ctxA = $ctx[$i]->toArray();
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA1 */
$ctxA1 = $ctxA[0];
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA2 */
$ctxA2 = $ctxA[1];
$str .= $ctxA1->toReverseString();
$str .= $ctxA2->toReverseString();
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = $ctx[4];
# size_t buflen;
$str .= implode('', array(
self::intToChr($ctx4 & 0xff),
self::intToChr(($ctx4 >> 8) & 0xff),
self::intToChr(($ctx4 >> 16) & 0xff),
self::intToChr(($ctx4 >> 24) & 0xff),
"\x00\x00\x00\x00"
/*
self::intToChr(($ctx4 >> 32) & 0xff),
self::intToChr(($ctx4 >> 40) & 0xff),
self::intToChr(($ctx4 >> 48) & 0xff),
self::intToChr(($ctx4 >> 56) & 0xff)
*/
));
# uint8_t last_node;
return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements, from
* a string (compatible with \Sodium\crypto_generichash_{init, update, final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function stringToContext($string)
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($string, (($i << 3) + 0), 8)
);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($string, 72 + (($i - 1) << 4), 8)
);
$ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($string, 64 + (($i - 1) << 4), 8)
);
}
# uint8_t buf[2 * 128];
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
# uint8_t buf[2 * 128];
$int = 0;
for ($i = 0; $i < 8; ++$i) {
$int |= self::chrToInt($string[352 + $i]) << ($i << 3);
}
$ctx[4] = $int;
return $ctx;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_SipHash', false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core32_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/
class ParagonIE_Sodium_Core32_SipHash extends ParagonIE_Sodium_Core32_Util
{
/**
* @internal You should not use this directly from another application
*
* @param array<int, ParagonIE_Sodium_Core32_Int64> $v
* @return array<int, ParagonIE_Sodium_Core32_Int64>
*/
public static function sipRound(array $v)
{
# v0 += v1;
$v[0] = $v[0]->addInt64($v[1]);
# v1 = ROTL(v1, 13);
$v[1] = $v[1]->rotateLeft(13);
# v1 ^= v0;
$v[1] = $v[1]->xorInt64($v[0]);
# v0=ROTL(v0,32);
$v[0] = $v[0]->rotateLeft(32);
# v2 += v3;
$v[2] = $v[2]->addInt64($v[3]);
# v3=ROTL(v3,16);
$v[3] = $v[3]->rotateLeft(16);
# v3 ^= v2;
$v[3] = $v[3]->xorInt64($v[2]);
# v0 += v3;
$v[0] = $v[0]->addInt64($v[3]);
# v3=ROTL(v3,21);
$v[3] = $v[3]->rotateLeft(21);
# v3 ^= v0;
$v[3] = $v[3]->xorInt64($v[0]);
# v2 += v1;
$v[2] = $v[2]->addInt64($v[1]);
# v1=ROTL(v1,17);
$v[1] = $v[1]->rotateLeft(17);
# v1 ^= v2;
$v[1] = $v[1]->xorInt64($v[2]);
# v2=ROTL(v2,32)
$v[2] = $v[2]->rotateLeft(32);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sipHash24($in, $key)
{
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(
new ParagonIE_Sodium_Core32_Int64(
array(0x736f, 0x6d65, 0x7073, 0x6575)
),
new ParagonIE_Sodium_Core32_Int64(
array(0x646f, 0x7261, 0x6e64, 0x6f6d)
),
new ParagonIE_Sodium_Core32_Int64(
array(0x6c79, 0x6765, 0x6e65, 0x7261)
),
new ParagonIE_Sodium_Core32_Int64(
array(0x7465, 0x6462, 0x7974, 0x6573)
)
);
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(
ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($key, 0, 8)
),
ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($key, 8, 8)
)
);
# b = ( ( u64 )inlen ) << 56;
$b = new ParagonIE_Sodium_Core32_Int64(
array(($inlen << 8) & 0xffff, 0, 0, 0)
);
# v3 ^= k1;
$v[3] = $v[3]->xorInt64($k[1]);
# v2 ^= k0;
$v[2] = $v[2]->xorInt64($k[0]);
# v1 ^= k1;
$v[1] = $v[1]->xorInt64($k[1]);
# v0 ^= k0;
$v[0] = $v[0]->xorInt64($k[0]);
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($in, 0, 8)
);
# v3 ^= m;
$v[3] = $v[3]->xorInt64($m);
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] = $v[0]->xorInt64($m);
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
0, self::chrToInt($in[6]) << 16
)
);
case 6:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
0, self::chrToInt($in[5]) << 8
)
);
case 5:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
0, self::chrToInt($in[4])
)
);
case 4:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[3]) << 24, 0
)
);
case 3:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[2]) << 16, 0
)
);
case 2:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[1]) << 8, 0
)
);
case 1:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[0]), 0
)
);
case 0:
break;
}
# v3 ^= b;
$v[3] = $v[3]->xorInt64($b);
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] = $v[0]->xorInt64($b);
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
# v2 ^= 0xff;
$v[2]->limbs[3] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return $v[0]
->xorInt64($v[1])
->xorInt64($v[2])
->xorInt64($v[3])
->toReverseString();
}
}
[30-Jul-2025 13:50:05 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[30-Jul-2025 13:50:42 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[20-Aug-2025 08:32:57 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[08-Sep-2025 07:30:10 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[08-Sep-2025 07:30:18 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:05:37 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:05:50 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:05:57 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:08 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:14 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:20 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:26 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:42 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:47 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:06:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:07:23 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:07:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Nov-2025 06:07:50 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Nov-2025 08:40:27 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:24:57 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:25:05 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:25:20 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:25:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:25:37 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:25:45 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:26:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:26:22 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:26:48 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:26:55 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:27:01 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:27:08 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[24-Nov-2025 09:27:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:08:06 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:08:16 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:08:47 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:09:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:09:05 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:09:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:09:42 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:09 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:14 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:34 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:36 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[26-Nov-2025 10:10:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:27:36 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:27:38 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:27:38 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:27:46 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:28:00 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:28:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:28:35 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:33:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:33:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:34:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[27-Nov-2025 12:34:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[28-Nov-2025 10:42:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[28-Nov-2025 10:43:05 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[30-Nov-2025 12:18:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[30-Nov-2025 12:18:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[30-Nov-2025 12:18:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[30-Nov-2025 12:18:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[30-Nov-2025 12:18:48 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[02-Dec-2025 10:43:01 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Poly1305.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Poly1305.php on line 10
[02-Dec-2025 10:43:02 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/ChaCha20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/ChaCha20.php on line 10
[02-Dec-2025 10:43:02 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/XChaCha20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/XChaCha20.php on line 10
[02-Dec-2025 10:43:02 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/HChaCha20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/HChaCha20.php on line 10
[02-Dec-2025 10:43:02 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Salsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/HSalsa20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/HSalsa20.php on line 10
[02-Dec-2025 10:43:02 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/X25519.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/X25519.php on line 10
[02-Dec-2025 10:43:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Util.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Util.php on line 10
[02-Dec-2025 10:43:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HSalsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/XSalsa20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/XSalsa20.php on line 10
[02-Dec-2025 10:43:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Salsa20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Salsa20.php on line 10
[02-Dec-2025 10:43:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/SipHash.php:12
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/SipHash.php on line 12
[02-Dec-2025 10:43:04 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Curve25519.php:16
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16
[02-Dec-2025 10:43:04 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[02-Dec-2025 10:43:04 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Curve25519.php:16
Stack trace:
#0 /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Ed25519.php(7): require_once()
#1 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16
[12-Dec-2025 13:28:08 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:28:10 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:28:11 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:28:19 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:28:22 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:35:17 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:35:26 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:35:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:35:55 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:36:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:36:12 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:38:17 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:38:18 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:38:23 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:38:24 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:38:24 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:38:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:42:59 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:01 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:03 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:05 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:13 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:55 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:57 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:58 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[12-Dec-2025 13:43:59 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[14-Dec-2025 14:38:42 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[14-Dec-2025 14:38:45 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[14-Dec-2025 14:38:46 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[14-Dec-2025 14:38:51 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[14-Dec-2025 14:38:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[14-Dec-2025 14:38:53 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[16-Dec-2025 15:09:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Dec-2025 15:49:02 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Dec-2025 15:49:31 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Dec-2025 15:49:34 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Dec-2025 15:49:35 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[18-Dec-2025 15:49:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[20-Dec-2025 16:24:27 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[20-Dec-2025 16:26:08 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[20-Dec-2025 16:26:12 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:24 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:28 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:43 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:45 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:37:53 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:38:00 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 03:38:35 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 17:04:00 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[22-Dec-2025 17:04:12 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[23-Dec-2025 09:47:29 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[23-Dec-2025 09:47:30 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[23-Dec-2025 09:47:32 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[23-Dec-2025 09:47:46 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[23-Dec-2025 09:48:01 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
[23-Dec-2025 09:48:07 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:13
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 13
<?php
if (class_exists('ParagonIE_Sodium_Core32_XSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_XSalsa20
*/
abstract class ParagonIE_Sodium_Core32_XSalsa20 extends ParagonIE_Sodium_Core32_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20($len, $nonce, $key)
{
$ret = self::salsa20(
$len,
self::substr($nonce, 16, 8),
self::hsalsa20($nonce, $key)
);
return $ret;
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::xsalsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
[02-Dec-2025 10:43:07 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20_Ctx" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/ChaCha20/IetfCtx.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/ChaCha20/IetfCtx.php on line 10
[02-Dec-2025 10:43:07 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/ChaCha20/Ctx.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/ChaCha20/Ctx.php on line 10
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx extends ParagonIE_Sodium_Core32_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($iv) !== 12) {
throw new InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.');
}
parent::__construct($key, self::substr($iv, 0, 8), $counter);
if (!empty($counter)) {
$this->container[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4));
}
$this->container[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
$this->container[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
$this->container[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 8, 4));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_Ctx
*/
class ParagonIE_Sodium_Core32_ChaCha20_Ctx extends ParagonIE_Sodium_Core32_Util implements ArrayAccess
{
/**
* @var SplFixedArray internally, <int, ParagonIE_Sodium_Core32_Int32>
*/
protected $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($key) !== 32) {
throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.');
}
$this->container = new SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$this->container[1] = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$this->container[2] = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$this->container[3] = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
$this->container[4] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
$this->container[5] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
$this->container[6] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
$this->container[7] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4));
$this->container[8] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4));
$this->container[9] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4));
$this->container[10] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4));
$this->container[11] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4));
if (empty($counter)) {
$this->container[12] = new ParagonIE_Sodium_Core32_Int32();
$this->container[13] = new ParagonIE_Sodium_Core32_Int32();
} else {
$this->container[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4));
$this->container[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 4, 4));
}
$this->container[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
$this->container[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int|ParagonIE_Sodium_Core32_Int32 $value
* @return void
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!is_int($offset)) {
throw new InvalidArgumentException('Expected an integer');
}
if ($value instanceof ParagonIE_Sodium_Core32_Int32) {
/*
} elseif (is_int($value)) {
$value = ParagonIE_Sodium_Core32_Int32::fromInt($value);
*/
} else {
throw new InvalidArgumentException('Expected an integer');
}
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
return isset($this->container[$offset])
? $this->container[$offset]
: null;
}
}
<?php
/**
* Class ParagonIE_Sodium_Core32_Int32
*
* Encapsulates a 32-bit integer.
*
* These are immutable. It always returns a new instance.
*/
class ParagonIE_Sodium_Core32_Int32
{
/**
* @var array<int, int> - two 16-bit integers
*
* 0 is the higher 16 bits
* 1 is the lower 16 bits
*/
public $limbs = array(0, 0);
/**
* @var int
*/
public $overflow = 0;
/**
* @var bool
*/
public $unsignedInt = false;
/**
* ParagonIE_Sodium_Core32_Int32 constructor.
* @param array $array
* @param bool $unsignedInt
*/
public function __construct($array = array(0, 0), $unsignedInt = false)
{
$this->limbs = array(
(int) $array[0],
(int) $array[1]
);
$this->overflow = 0;
$this->unsignedInt = $unsignedInt;
}
/**
* Adds two int32 objects
*
* @param ParagonIE_Sodium_Core32_Int32 $addend
* @return ParagonIE_Sodium_Core32_Int32
*/
public function addInt32(ParagonIE_Sodium_Core32_Int32 $addend)
{
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$j0 = $addend->limbs[0];
$j1 = $addend->limbs[1];
$r1 = $i1 + ($j1 & 0xffff);
$carry = $r1 >> 16;
$r0 = $i0 + ($j0 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int32(
array($r0, $r1)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* Adds a normal integer to an int32 object
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function addInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
/** @var int $int */
$int = (int) $int;
$int = (int) $int;
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$r1 = $i1 + ($int & 0xffff);
$carry = $r1 >> 16;
$r0 = $i0 + (($int >> 16) & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int32(
array($r0, $r1)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param int $b
* @return int
*/
public function compareInt($b = 0)
{
$gt = 0;
$eq = 1;
$i = 2;
$j = 0;
while ($i > 0) {
--$i;
/** @var int $x1 */
$x1 = $this->limbs[$i];
/** @var int $x2 */
$x2 = ($b >> ($j << 4)) & 0xffff;
/** @var int $gt */
$gt |= (($x2 - $x1) >> 8) & $eq;
/** @var int $eq */
$eq &= (($x2 ^ $x1) - 1) >> 8;
}
return ($gt + $gt - $eq) + 1;
}
/**
* @param int $m
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mask($m = 0)
{
/** @var int $hi */
$hi = ((int) $m >> 16);
$hi &= 0xffff;
/** @var int $lo */
$lo = ((int) $m) & 0xffff;
return new ParagonIE_Sodium_Core32_Int32(
array(
(int) ($this->limbs[0] & $hi),
(int) ($this->limbs[1] & $lo)
),
$this->unsignedInt
);
}
/**
* @param array<int, int> $a
* @param array<int, int> $b
* @param int $baseLog2
* @return array<int, int>
*/
public function multiplyLong(array $a, array $b, $baseLog2 = 16)
{
$a_l = count($a);
$b_l = count($b);
/** @var array<int, int> $r */
$r = array_fill(0, $a_l + $b_l + 1, 0);
$base = 1 << $baseLog2;
for ($i = 0; $i < $a_l; ++$i) {
$a_i = $a[$i];
for ($j = 0; $j < $a_l; ++$j) {
$b_j = $b[$j];
$product = ($a_i * $b_j) + $r[$i + $j];
$carry = ((int) $product >> $baseLog2 & 0xffff);
$r[$i + $j] = ((int) $product - (int) ($carry * $base)) & 0xffff;
$r[$i + $j + 1] += $carry;
}
}
return array_slice($r, 0, 5);
}
/**
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mulIntFast($int)
{
// Handle negative numbers
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($int >> 31) & 1;
$a = array_reverse($this->limbs);
$b = array(
$int & 0xffff,
($int >> 16) & 0xffff
);
if ($aNeg) {
for ($i = 0; $i < 2; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 2; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
// Multiply
$res = $this->multiplyLong($a, $b);
// Re-apply negation to results
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 2; ++$i) {
$res[$i] = (0xffff ^ $res[$i]) & 0xffff;
}
// Handle integer overflow
$c = 1;
for ($i = 0; $i < 2; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
// Return our values
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs = array(
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 2) {
$return->overflow = $res[2] & 0xffff;
}
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int32 $right
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mulInt32Fast(ParagonIE_Sodium_Core32_Int32 $right)
{
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($right->limbs[0] >> 15) & 1;
$a = array_reverse($this->limbs);
$b = array_reverse($right->limbs);
if ($aNeg) {
for ($i = 0; $i < 2; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 2; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
$res = $this->multiplyLong($a, $b);
if ($aNeg !== $bNeg) {
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 2; ++$i) {
$res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
}
$c = 1;
for ($i = 0; $i < 2; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
}
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs = array(
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 2) {
$return->overflow = $res[2];
}
return $return;
}
/**
* @param int $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function mulInt($int = 0, $size = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulIntFast((int) $int);
}
/** @var int $int */
$int = (int) $int;
/** @var int $size */
$size = (int) $size;
if (!$size) {
$size = 31;
}
/** @var int $size */
$a = clone $this;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$m = (int) (-($int & 1));
$x0 = $a0 & $m;
$x1 = $a1 & $m;
$ret1 += $x1;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$a1 = ($a1 << 1);
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$int >>= 1;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int32 $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function mulInt32(ParagonIE_Sodium_Core32_Int32 $int, $size = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulInt32Fast($int);
}
if (!$size) {
$size = 31;
}
/** @var int $size */
$a = clone $this;
$b = clone $int;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$b0 = $b->limbs[0];
$b1 = $b->limbs[1];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$m = (int) (-($b1 & 1));
$x0 = $a0 & $m;
$x1 = $a1 & $m;
$ret1 += $x1;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$a1 = ($a1 << 1);
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$x0 = ($b0 & 1) << 16;
$b0 = ($b0 >> 1);
$b1 = (($b1 | $x0) >> 1);
$b0 &= 0xffff;
$b1 &= 0xffff;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
return $return;
}
/**
* OR this 32-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function orInt32(ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] | $b->limbs[0]),
(int) ($this->limbs[1] | $b->limbs[1])
);
/** @var int overflow */
$return->overflow = $this->overflow | $b->overflow;
return $return;
}
/**
* @param int $b
* @return bool
*/
public function isGreaterThan($b = 0)
{
return $this->compareInt($b) > 0;
}
/**
* @param int $b
* @return bool
*/
public function isLessThanInt($b = 0)
{
return $this->compareInt($b) < 0;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 31;
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var int $c */
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 1;
/** @var int $sub_shift */
$sub_shift = $c & 15;
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
for ($i = 1; $i >= 0; --$i) {
/** @var int $j */
$j = ($i + $idx_shift) & 1;
/** @var int $k */
$k = ($i + $idx_shift + 1) & 1;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) << $sub_shift)
|
((int) ($myLimbs[$k]) >> (16 - $sub_shift))
) & 0xffff
);
}
}
return $return;
}
/**
* Rotate to the right
*
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 31;
/** @var int $c */
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var int $c */
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 1;
/** @var int $sub_shift */
$sub_shift = $c & 15;
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
for ($i = 1; $i >= 0; --$i) {
/** @var int $j */
$j = ($i - $idx_shift) & 1;
/** @var int $k */
$k = ($i - $idx_shift - 1) & 1;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) >> (int) ($sub_shift))
|
((int) ($myLimbs[$k]) << (16 - (int) ($sub_shift)))
) & 0xffff
);
}
}
return $return;
}
/**
* @param bool $bool
* @return self
*/
public function setUnsignedInt($bool = false)
{
$this->unsignedInt = !empty($bool);
return $this;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function shiftLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftRight(-$c);
} else {
/** @var int $c */
/** @var int $tmp */
$tmp = $this->limbs[1] << $c;
$return->limbs[1] = (int)($tmp & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
/** @var int $tmp */
$tmp = ($this->limbs[0] << $c) | ($carry & 0xffff);
$return->limbs[0] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public function shiftRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c >= 16) {
$return->limbs = array(
(int) ($this->overflow & 0xffff),
(int) ($this->limbs[0])
);
$return->overflow = $this->overflow >> 16;
return $return->shiftRight($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftLeft(-$c);
} else {
if (!is_int($c)) {
throw new TypeError();
}
/** @var int $c */
// $return->limbs[0] = (int) (($this->limbs[0] >> $c) & 0xffff);
$carryLeft = (int) ($this->overflow & ((1 << ($c + 1)) - 1));
$return->limbs[0] = (int) ((($this->limbs[0] >> $c) | ($carryLeft << (16 - $c))) & 0xffff);
$carryRight = (int) ($this->limbs[0] & ((1 << ($c + 1)) - 1));
$return->limbs[1] = (int) ((($this->limbs[1] >> $c) | ($carryRight << (16 - $c))) & 0xffff);
$return->overflow >>= $c;
}
return $return;
}
/**
* Subtract a normal integer from an int32 object.
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function subInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
/** @var int $int */
$int = (int) $int;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
/** @var int $tmp */
$tmp = $this->limbs[1] - ($int & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $tmp */
$tmp = $this->limbs[0] - (($int >> 16) & 0xffff) + $carry;
$return->limbs[0] = (int) ($tmp & 0xffff);
return $return;
}
/**
* Subtract two int32 objects from each other
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function subInt32(ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
/** @var int $tmp */
$tmp = $this->limbs[1] - ($b->limbs[1] & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $tmp */
$tmp = $this->limbs[0] - ($b->limbs[0] & 0xffff) + $carry;
$return->limbs[0] = (int) ($tmp & 0xffff);
return $return;
}
/**
* XOR this 32-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function xorInt32(ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] ^ $b->limbs[0]),
(int) ($this->limbs[1] ^ $b->limbs[1])
);
return $return;
}
/**
* @param int $signed
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInt($signed)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($signed, 'int', 1);;
/** @var int $signed */
$signed = (int) $signed;
return new ParagonIE_Sodium_Core32_Int32(
array(
(int) (($signed >> 16) & 0xffff),
(int) ($signed & 0xffff)
)
);
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
throw new RangeException(
'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8);
$return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff);
$return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8);
$return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff);
return $return;
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromReverseString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
throw new RangeException(
'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8);
$return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff);
$return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8);
$return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff);
return $return;
}
/**
* @return array<int, int>
*/
public function toArray()
{
return array((int) ($this->limbs[0] << 16 | $this->limbs[1]));
}
/**
* @return string
* @throws TypeError
*/
public function toString()
{
return
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff);
}
/**
* @return int
*/
public function toInt()
{
return (int) (
(($this->limbs[0] & 0xffff) << 16)
|
($this->limbs[1] & 0xffff)
);
}
/**
* @return ParagonIE_Sodium_Core32_Int32
*/
public function toInt32()
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ($this->limbs[0] & 0xffff);
$return->limbs[1] = (int) ($this->limbs[1] & 0xffff);
$return->unsignedInt = $this->unsignedInt;
$return->overflow = (int) ($this->overflow & 0x7fffffff);
return $return;
}
/**
* @return ParagonIE_Sodium_Core32_Int64
*/
public function toInt64()
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
if ($this->unsignedInt) {
$return->limbs[0] += (($this->overflow >> 16) & 0xffff);
$return->limbs[1] += (($this->overflow) & 0xffff);
} else {
$neg = -(($this->limbs[0] >> 15) & 1);
$return->limbs[0] = (int)($neg & 0xffff);
$return->limbs[1] = (int)($neg & 0xffff);
}
$return->limbs[2] = (int) ($this->limbs[0] & 0xffff);
$return->limbs[3] = (int) ($this->limbs[1] & 0xffff);
return $return;
}
/**
* @return string
* @throws TypeError
*/
public function toReverseString()
{
return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->toString();
} catch (TypeError $ex) {
// PHP engine can't handle exceptions from __toString()
return '';
}
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Util', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core32_Util extends ParagonIE_Sodium_Core_Util
{
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Salsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Salsa20
*/
abstract class ParagonIE_Sodium_Core32_Salsa20 extends ParagonIE_Sodium_Core32_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function core_salsa20($in, $k, $c = null)
{
/**
* @var ParagonIE_Sodium_Core32_Int32 $x0
* @var ParagonIE_Sodium_Core32_Int32 $x1
* @var ParagonIE_Sodium_Core32_Int32 $x2
* @var ParagonIE_Sodium_Core32_Int32 $x3
* @var ParagonIE_Sodium_Core32_Int32 $x4
* @var ParagonIE_Sodium_Core32_Int32 $x5
* @var ParagonIE_Sodium_Core32_Int32 $x6
* @var ParagonIE_Sodium_Core32_Int32 $x7
* @var ParagonIE_Sodium_Core32_Int32 $x8
* @var ParagonIE_Sodium_Core32_Int32 $x9
* @var ParagonIE_Sodium_Core32_Int32 $x10
* @var ParagonIE_Sodium_Core32_Int32 $x11
* @var ParagonIE_Sodium_Core32_Int32 $x12
* @var ParagonIE_Sodium_Core32_Int32 $x13
* @var ParagonIE_Sodium_Core32_Int32 $x14
* @var ParagonIE_Sodium_Core32_Int32 $x15
* @var ParagonIE_Sodium_Core32_Int32 $j0
* @var ParagonIE_Sodium_Core32_Int32 $j1
* @var ParagonIE_Sodium_Core32_Int32 $j2
* @var ParagonIE_Sodium_Core32_Int32 $j3
* @var ParagonIE_Sodium_Core32_Int32 $j4
* @var ParagonIE_Sodium_Core32_Int32 $j5
* @var ParagonIE_Sodium_Core32_Int32 $j6
* @var ParagonIE_Sodium_Core32_Int32 $j7
* @var ParagonIE_Sodium_Core32_Int32 $j8
* @var ParagonIE_Sodium_Core32_Int32 $j9
* @var ParagonIE_Sodium_Core32_Int32 $j10
* @var ParagonIE_Sodium_Core32_Int32 $j11
* @var ParagonIE_Sodium_Core32_Int32 $j12
* @var ParagonIE_Sodium_Core32_Int32 $j13
* @var ParagonIE_Sodium_Core32_Int32 $j14
* @var ParagonIE_Sodium_Core32_Int32 $j15
*/
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$x0 = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$x5 = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$x10 = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$x15 = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
} else {
$x0 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$x5 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$x10 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$x15 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$x1 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4));
$x2 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4));
$x3 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4));
$x4 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4));
$x6 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$x7 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$x8 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$x9 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
$x11 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4));
$x12 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4));
$x13 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4));
$x14 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4));
$j0 = clone $x0;
$j1 = clone $x1;
$j2 = clone $x2;
$j3 = clone $x3;
$j4 = clone $x4;
$j5 = clone $x5;
$j6 = clone $x6;
$j7 = clone $x7;
$j8 = clone $x8;
$j9 = clone $x9;
$j10 = clone $x10;
$j11 = clone $x11;
$j12 = clone $x12;
$j13 = clone $x13;
$j14 = clone $x14;
$j15 = clone $x15;
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 = $x4->xorInt32($x0->addInt32($x12)->rotateLeft(7));
$x8 = $x8->xorInt32($x4->addInt32($x0)->rotateLeft(9));
$x12 = $x12->xorInt32($x8->addInt32($x4)->rotateLeft(13));
$x0 = $x0->xorInt32($x12->addInt32($x8)->rotateLeft(18));
$x9 = $x9->xorInt32($x5->addInt32($x1)->rotateLeft(7));
$x13 = $x13->xorInt32($x9->addInt32($x5)->rotateLeft(9));
$x1 = $x1->xorInt32($x13->addInt32($x9)->rotateLeft(13));
$x5 = $x5->xorInt32($x1->addInt32($x13)->rotateLeft(18));
$x14 = $x14->xorInt32($x10->addInt32($x6)->rotateLeft(7));
$x2 = $x2->xorInt32($x14->addInt32($x10)->rotateLeft(9));
$x6 = $x6->xorInt32($x2->addInt32($x14)->rotateLeft(13));
$x10 = $x10->xorInt32($x6->addInt32($x2)->rotateLeft(18));
$x3 = $x3->xorInt32($x15->addInt32($x11)->rotateLeft(7));
$x7 = $x7->xorInt32($x3->addInt32($x15)->rotateLeft(9));
$x11 = $x11->xorInt32($x7->addInt32($x3)->rotateLeft(13));
$x15 = $x15->xorInt32($x11->addInt32($x7)->rotateLeft(18));
$x1 = $x1->xorInt32($x0->addInt32($x3)->rotateLeft(7));
$x2 = $x2->xorInt32($x1->addInt32($x0)->rotateLeft(9));
$x3 = $x3->xorInt32($x2->addInt32($x1)->rotateLeft(13));
$x0 = $x0->xorInt32($x3->addInt32($x2)->rotateLeft(18));
$x6 = $x6->xorInt32($x5->addInt32($x4)->rotateLeft(7));
$x7 = $x7->xorInt32($x6->addInt32($x5)->rotateLeft(9));
$x4 = $x4->xorInt32($x7->addInt32($x6)->rotateLeft(13));
$x5 = $x5->xorInt32($x4->addInt32($x7)->rotateLeft(18));
$x11 = $x11->xorInt32($x10->addInt32($x9)->rotateLeft(7));
$x8 = $x8->xorInt32($x11->addInt32($x10)->rotateLeft(9));
$x9 = $x9->xorInt32($x8->addInt32($x11)->rotateLeft(13));
$x10 = $x10->xorInt32($x9->addInt32($x8)->rotateLeft(18));
$x12 = $x12->xorInt32($x15->addInt32($x14)->rotateLeft(7));
$x13 = $x13->xorInt32($x12->addInt32($x15)->rotateLeft(9));
$x14 = $x14->xorInt32($x13->addInt32($x12)->rotateLeft(13));
$x15 = $x15->xorInt32($x14->addInt32($x13)->rotateLeft(18));
}
$x0 = $x0->addInt32($j0);
$x1 = $x1->addInt32($j1);
$x2 = $x2->addInt32($j2);
$x3 = $x3->addInt32($j3);
$x4 = $x4->addInt32($j4);
$x5 = $x5->addInt32($j5);
$x6 = $x6->addInt32($j6);
$x7 = $x7->addInt32($j7);
$x8 = $x8->addInt32($j8);
$x9 = $x9->addInt32($j9);
$x10 = $x10->addInt32($j10);
$x11 = $x11->addInt32($j11);
$x12 = $x12->addInt32($j12);
$x13 = $x13->addInt32($j13);
$x14 = $x14->addInt32($j14);
$x15 = $x15->addInt32($j15);
return $x0->toReverseString() .
$x1->toReverseString() .
$x2->toReverseString() .
$x3->toReverseString() .
$x4->toReverseString() .
$x5->toReverseString() .
$x6->toReverseString() .
$x7->toReverseString() .
$x8->toReverseString() .
$x9->toReverseString() .
$x10->toReverseString() .
$x11->toReverseString() .
$x12->toReverseString() .
$x13->toReverseString() .
$x14->toReverseString() .
$x15->toReverseString();
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20($len, $nonce, $key)
{
if (self::strlen($key) !== 32) {
throw new RangeException('Key must be 32 bytes long');
}
$kcopy = '' . $key;
$in = self::substr($nonce, 0, 8) . str_repeat("\0", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy, null);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(
self::core_salsa20($in, $kcopy, null),
0,
$len
);
}
try {
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic($m, $n, $ic, $k)
{
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= ParagonIE_Sodium_Core32_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, 64),
self::substr($block, 0, 64)
);
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, $mlen),
self::substr($block, 0, $mlen)
);
}
try {
ParagonIE_Sodium_Compat::memzero($block);
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::salsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Fe', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Fe
*
* This represents a Field Element
*/
class ParagonIE_Sodium_Core32_Curve25519_Fe implements ArrayAccess
{
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
protected $container = array();
/**
* @var int
*/
protected $size = 10;
/**
* @internal You should not use this directly from another application
*
* @param array<int, ParagonIE_Sodium_Core32_Int32> $array
* @param bool $save_indexes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
$obj = new ParagonIE_Sodium_Core32_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$array[$i]->overflow = 0;
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
if (!($array[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new TypeError('Expected ParagonIE_Sodium_Core32_Int32');
}
$array[$i]->overflow = 0;
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromIntArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
$set = array();
/** @var int $i */
/** @var int $v */
foreach ($array as $i => $v) {
$set[$i] = ParagonIE_Sodium_Core32_Int32::fromInt($v);
}
$obj = new ParagonIE_Sodium_Core32_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$set[$i]->overflow = 0;
$obj->offsetSet($keys[$i], $set[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$set[$i]->overflow = 0;
$obj->offsetSet($i, $set[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @param mixed $value
* @return void
* @throws SodiumException
* @throws TypeError
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!($value instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new InvalidArgumentException('Expected an instance of ParagonIE_Sodium_Core32_Int32');
}
if (is_null($offset)) {
$this->container[] = $value;
} else {
ParagonIE_Sodium_Core32_Util::declareScalarType($offset, 'int', 1);
$this->container[(int) $offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return ParagonIE_Sodium_Core32_Int32
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->container[$offset])) {
$this->container[(int) $offset] = new ParagonIE_Sodium_Core32_Int32();
}
/** @var ParagonIE_Sodium_Core32_Int32 $get */
$get = $this->container[$offset];
return $get;
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
if (empty($this->container)) {
return array();
}
$c = array(
(int) ($this->container[0]->toInt()),
(int) ($this->container[1]->toInt()),
(int) ($this->container[2]->toInt()),
(int) ($this->container[3]->toInt()),
(int) ($this->container[4]->toInt()),
(int) ($this->container[5]->toInt()),
(int) ($this->container[6]->toInt()),
(int) ($this->container[7]->toInt()),
(int) ($this->container[8]->toInt()),
(int) ($this->container[9]->toInt())
);
return array(implode(', ', $c));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_H', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_H
*
* This just contains the constants in the ref10/base.h file
*/
class ParagonIE_Sodium_Core32_Curve25519_H extends ParagonIE_Sodium_Core32_Util
{
/**
* See: libsodium's crypto_core/curve25519/ref10/base.h
*
* @var array<int, array<int, array<int, array<int, int>>>> Basically, int[32][8][3][10]
*/
protected static $base = array(
array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303),
array(-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081),
array(26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540),
array(23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397),
array(7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777),
array(-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737),
array(-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300),
),
array(
array(14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726),
array(-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955),
array(27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425),
),
),
array(
array(
array(-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171),
array(27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510),
array(17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660),
),
array(
array(-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639),
array(29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963),
array(5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950),
),
array(
array(-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568),
array(12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335),
array(25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628),
),
array(
array(-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007),
array(-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772),
array(-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653),
),
array(
array(2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567),
array(13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686),
array(21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372),
),
array(
array(-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887),
array(-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954),
array(-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953),
),
array(
array(24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833),
array(-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532),
array(-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876),
),
array(
array(2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268),
array(33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214),
array(1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038),
),
),
array(
array(
array(6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800),
array(4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645),
array(-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664),
),
array(
array(1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933),
array(-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182),
array(-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222),
),
array(
array(-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991),
array(20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880),
array(9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092),
),
array(
array(-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295),
array(19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788),
array(8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553),
),
array(
array(-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026),
array(11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347),
array(-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033),
),
array(
array(-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395),
array(-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278),
array(1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890),
),
array(
array(32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995),
array(-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596),
array(-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891),
),
array(
array(31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060),
array(11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608),
array(-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606),
),
),
array(
array(
array(7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389),
array(-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016),
array(-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341),
),
array(
array(-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505),
array(14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553),
array(-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655),
),
array(
array(15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220),
array(12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631),
array(-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099),
),
array(
array(26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556),
array(14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749),
array(236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930),
),
array(
array(1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391),
array(5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253),
array(20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066),
),
array(
array(24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958),
array(-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082),
array(-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383),
),
array(
array(-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521),
array(-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807),
array(23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948),
),
array(
array(9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134),
array(-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455),
array(27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629),
),
),
array(
array(
array(-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069),
array(-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746),
array(24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919),
),
array(
array(11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837),
array(8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906),
array(-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771),
),
array(
array(-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817),
array(10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098),
array(10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409),
),
array(
array(-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504),
array(-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727),
array(28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420),
),
array(
array(-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003),
array(-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605),
array(-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384),
),
array(
array(-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701),
array(-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683),
array(29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708),
),
array(
array(-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563),
array(-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260),
array(-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387),
),
array(
array(-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672),
array(23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686),
array(-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665),
),
),
array(
array(
array(11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182),
array(-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277),
array(14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628),
),
array(
array(-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474),
array(-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539),
array(-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822),
),
array(
array(-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970),
array(19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756),
array(-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508),
),
array(
array(-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683),
array(-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655),
array(-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158),
),
array(
array(-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125),
array(-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839),
array(-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664),
),
array(
array(27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294),
array(-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899),
array(-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070),
),
array(
array(3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294),
array(-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949),
array(-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083),
),
array(
array(31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420),
array(-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940),
array(29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396),
),
),
array(
array(
array(-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567),
array(20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127),
array(-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294),
),
array(
array(-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887),
array(22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964),
array(16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195),
),
array(
array(9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244),
array(24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999),
array(-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762),
),
array(
array(-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274),
array(-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236),
array(-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605),
),
array(
array(-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761),
array(-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884),
array(-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482),
),
array(
array(-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638),
array(-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490),
array(-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170),
),
array(
array(5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736),
array(10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124),
array(-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392),
),
array(
array(8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029),
array(6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048),
array(28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958),
),
),
array(
array(
array(24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593),
array(26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071),
array(-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692),
),
array(
array(11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687),
array(-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441),
array(-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001),
),
array(
array(-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460),
array(-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007),
array(-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762),
),
array(
array(15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005),
array(-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674),
array(4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035),
),
array(
array(7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590),
array(-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957),
array(-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812),
),
array(
array(33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740),
array(-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122),
array(-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158),
),
array(
array(8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885),
array(26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140),
array(19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857),
),
array(
array(801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155),
array(19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260),
array(19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483),
),
),
array(
array(
array(-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677),
array(32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815),
array(22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751),
),
array(
array(-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203),
array(-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208),
array(1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230),
),
array(
array(16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850),
array(-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389),
array(-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968),
),
array(
array(-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689),
array(14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880),
array(5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304),
),
array(
array(30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632),
array(-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412),
array(20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566),
),
array(
array(-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038),
array(-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232),
array(-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943),
),
array(
array(17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856),
array(23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738),
array(15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971),
),
array(
array(-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718),
array(-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697),
array(-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883),
),
),
array(
array(
array(5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912),
array(-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358),
array(3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849),
),
array(
array(29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307),
array(-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977),
array(-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335),
),
array(
array(-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644),
array(-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616),
array(-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735),
),
array(
array(-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099),
array(29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341),
array(-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336),
),
array(
array(-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646),
array(31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425),
array(-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388),
),
array(
array(-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743),
array(-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822),
array(-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462),
),
array(
array(18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985),
array(9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702),
array(-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797),
),
array(
array(21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293),
array(27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100),
array(19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688),
),
),
array(
array(
array(12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186),
array(2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610),
array(-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707),
),
array(
array(7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220),
array(915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025),
array(32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044),
),
array(
array(32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992),
array(-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027),
array(21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197),
),
array(
array(8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901),
array(31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952),
array(19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878),
),
array(
array(-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390),
array(32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730),
array(2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730),
),
array(
array(-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180),
array(-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272),
array(-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715),
),
array(
array(-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970),
array(-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772),
array(-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865),
),
array(
array(15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750),
array(20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373),
array(32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348),
),
),
array(
array(
array(9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144),
array(-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195),
array(5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086),
),
array(
array(-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684),
array(-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518),
array(-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233),
),
array(
array(-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793),
array(-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794),
array(580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435),
),
array(
array(23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921),
array(13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518),
array(2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563),
),
array(
array(14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278),
array(-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024),
array(4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030),
),
array(
array(10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783),
array(27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717),
array(6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844),
),
array(
array(14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333),
array(16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048),
array(22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760),
),
array(
array(-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760),
array(-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757),
array(-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112),
),
),
array(
array(
array(-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468),
array(3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184),
array(10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289),
),
array(
array(15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066),
array(24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882),
array(13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226),
),
array(
array(16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101),
array(29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279),
array(-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811),
),
array(
array(27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709),
array(20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714),
array(-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121),
),
array(
array(9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464),
array(12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847),
array(13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400),
),
array(
array(4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414),
array(-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158),
array(17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045),
),
array(
array(-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415),
array(-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459),
array(-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079),
),
array(
array(21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412),
array(-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743),
array(-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836),
),
),
array(
array(
array(12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022),
array(18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429),
array(-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065),
),
array(
array(30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861),
array(10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000),
array(-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101),
),
array(
array(32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815),
array(29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642),
array(10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966),
),
array(
array(25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574),
array(-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742),
array(-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689),
),
array(
array(12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020),
array(-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772),
array(3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982),
),
array(
array(-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953),
array(-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218),
array(-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265),
),
array(
array(29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073),
array(-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325),
array(-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798),
),
array(
array(-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870),
array(-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863),
array(-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927),
),
),
array(
array(
array(-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267),
array(-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663),
array(22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862),
),
array(
array(-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673),
array(15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943),
array(15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020),
),
array(
array(-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238),
array(11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064),
array(14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795),
),
array(
array(15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052),
array(-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904),
array(29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531),
),
array(
array(-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979),
array(-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841),
array(10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431),
),
array(
array(10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324),
array(-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940),
array(10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320),
),
array(
array(-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184),
array(14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114),
array(30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878),
),
array(
array(12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784),
array(-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091),
array(-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585),
),
),
array(
array(
array(-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208),
array(10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864),
array(17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661),
),
array(
array(7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233),
array(26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212),
array(-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525),
),
array(
array(-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068),
array(9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397),
array(-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988),
),
array(
array(5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889),
array(32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038),
array(14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697),
),
array(
array(20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875),
array(-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905),
array(-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656),
),
array(
array(11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818),
array(27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714),
array(10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203),
),
array(
array(20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931),
array(-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024),
array(-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084),
),
array(
array(-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204),
array(20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817),
array(27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667),
),
),
array(
array(
array(11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504),
array(-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768),
array(-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255),
),
array(
array(6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790),
array(1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438),
array(-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333),
),
array(
array(17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971),
array(31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905),
array(29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409),
),
array(
array(12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409),
array(6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499),
array(-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363),
),
array(
array(28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664),
array(-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324),
array(-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940),
),
array(
array(13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990),
array(-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914),
array(-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290),
),
array(
array(24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257),
array(-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433),
array(-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236),
),
array(
array(-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045),
array(11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093),
array(-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347),
),
),
array(
array(
array(-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191),
array(-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507),
array(-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906),
),
array(
array(3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018),
array(-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109),
array(-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926),
),
array(
array(-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528),
array(8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625),
array(-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286),
),
array(
array(2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033),
array(27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866),
array(21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896),
),
array(
array(30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075),
array(26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347),
array(-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437),
),
array(
array(-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165),
array(-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588),
array(-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193),
),
array(
array(-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017),
array(-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883),
array(21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961),
),
array(
array(8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043),
array(29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663),
array(-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362),
),
),
array(
array(
array(-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860),
array(2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466),
array(-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063),
),
array(
array(-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997),
array(-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295),
array(-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369),
),
array(
array(9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385),
array(18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109),
array(2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906),
),
array(
array(4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424),
array(-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185),
array(7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962),
),
array(
array(-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325),
array(10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593),
array(696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404),
),
array(
array(-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644),
array(17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801),
array(26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804),
),
array(
array(-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884),
array(-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577),
array(-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849),
),
array(
array(32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473),
array(-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644),
array(-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319),
),
),
array(
array(
array(-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599),
array(-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768),
array(-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084),
),
array(
array(-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328),
array(-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369),
array(20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920),
),
array(
array(12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815),
array(-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025),
array(-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397),
),
array(
array(-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448),
array(6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981),
array(30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165),
),
array(
array(32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501),
array(17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073),
array(-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861),
),
array(
array(14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845),
array(-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211),
array(18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870),
),
array(
array(10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096),
array(33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803),
array(-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168),
),
array(
array(30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965),
array(-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505),
array(18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598),
),
),
array(
array(
array(5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782),
array(5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900),
array(-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479),
),
array(
array(-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208),
array(8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232),
array(17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719),
),
array(
array(16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271),
array(-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326),
array(-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132),
),
array(
array(14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300),
array(8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570),
array(15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670),
),
array(
array(-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994),
array(-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913),
array(31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317),
),
array(
array(-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730),
array(842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096),
array(-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078),
),
array(
array(-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411),
array(-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905),
array(-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654),
),
array(
array(-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870),
array(-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498),
array(12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579),
),
),
array(
array(
array(14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677),
array(10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647),
array(-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743),
),
array(
array(-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468),
array(21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375),
array(-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155),
),
array(
array(6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725),
array(-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612),
array(-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943),
),
array(
array(-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944),
array(30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928),
array(9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406),
),
array(
array(22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139),
array(-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963),
array(-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693),
),
array(
array(1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734),
array(-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680),
array(-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410),
),
array(
array(-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931),
array(-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654),
array(22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710),
),
array(
array(29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180),
array(-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684),
array(-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895),
),
),
array(
array(
array(22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501),
array(-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413),
array(6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880),
),
array(
array(-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874),
array(22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962),
array(-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899),
),
array(
array(21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152),
array(9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063),
array(7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080),
),
array(
array(-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146),
array(-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183),
array(-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133),
),
array(
array(-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421),
array(-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622),
array(-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197),
),
array(
array(2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663),
array(31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753),
array(4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755),
),
array(
array(-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862),
array(-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118),
array(26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171),
),
array(
array(15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380),
array(16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824),
array(28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270),
),
),
array(
array(
array(-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438),
array(-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584),
array(-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562),
),
array(
array(30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471),
array(18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610),
array(19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269),
),
array(
array(-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650),
array(14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369),
array(19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461),
),
array(
array(30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462),
array(-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793),
array(-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218),
),
array(
array(-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226),
array(18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019),
array(-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037),
),
array(
array(31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171),
array(-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132),
array(-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841),
),
array(
array(21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181),
array(-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210),
array(-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040),
),
array(
array(3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935),
array(24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105),
array(-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814),
),
),
array(
array(
array(793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852),
array(5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581),
array(-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646),
),
array(
array(10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844),
array(10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025),
array(27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453),
),
array(
array(-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068),
array(4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192),
array(-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921),
),
array(
array(-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259),
array(-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426),
array(-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072),
),
array(
array(-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305),
array(13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832),
array(28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943),
),
array(
array(-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011),
array(24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447),
array(17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494),
),
array(
array(-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245),
array(-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859),
array(28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915),
),
array(
array(16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707),
array(10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848),
array(-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224),
),
),
array(
array(
array(-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391),
array(15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215),
array(-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101),
),
array(
array(23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713),
array(21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849),
array(-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930),
),
array(
array(-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940),
array(-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031),
array(-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404),
),
array(
array(-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243),
array(-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116),
array(-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525),
),
array(
array(-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509),
array(-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883),
array(15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865),
),
array(
array(-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660),
array(4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273),
array(-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138),
),
array(
array(-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560),
array(-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135),
array(2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941),
),
array(
array(-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739),
array(18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756),
array(-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819),
),
),
array(
array(
array(-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347),
array(-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028),
array(21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075),
),
array(
array(16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799),
array(-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609),
array(-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817),
),
array(
array(-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989),
array(-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523),
array(4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278),
),
array(
array(31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045),
array(19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377),
array(24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480),
),
array(
array(17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016),
array(510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426),
array(18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525),
),
array(
array(13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396),
array(9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080),
array(12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892),
),
array(
array(15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275),
array(11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074),
array(20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140),
),
array(
array(-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717),
array(-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101),
array(24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127),
),
),
array(
array(
array(-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632),
array(-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415),
array(-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160),
),
array(
array(31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876),
array(22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625),
array(-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478),
),
array(
array(27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164),
array(26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595),
array(-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248),
),
array(
array(-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858),
array(15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193),
array(8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184),
),
array(
array(-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942),
array(-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635),
array(21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948),
),
array(
array(11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935),
array(-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415),
array(-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416),
),
array(
array(-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018),
array(4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778),
array(366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659),
),
array(
array(-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385),
array(18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503),
array(476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329),
),
),
array(
array(
array(20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056),
array(-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838),
array(24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948),
),
array(
array(-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691),
array(-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118),
array(-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517),
),
array(
array(-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269),
array(-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904),
array(-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589),
),
array(
array(-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193),
array(-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910),
array(-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930),
),
array(
array(-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667),
array(25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481),
array(-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876),
),
array(
array(22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640),
array(-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278),
array(-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112),
),
array(
array(26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272),
array(17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012),
array(-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221),
),
array(
array(30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046),
array(13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345),
array(-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310),
),
),
array(
array(
array(19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937),
array(31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636),
array(-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008),
),
array(
array(-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429),
array(-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576),
array(31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066),
),
array(
array(-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490),
array(-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104),
array(33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053),
),
array(
array(31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275),
array(-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511),
array(22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095),
),
array(
array(-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439),
array(23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939),
array(-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424),
),
array(
array(2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310),
array(3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608),
array(-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079),
),
array(
array(-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101),
array(21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418),
array(18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576),
),
array(
array(30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356),
array(9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996),
array(-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099),
),
),
array(
array(
array(-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728),
array(-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658),
array(-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242),
),
array(
array(-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001),
array(-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766),
array(18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373),
),
array(
array(26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458),
array(-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628),
array(-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657),
),
array(
array(-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062),
array(25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616),
array(31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014),
),
array(
array(24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383),
array(-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814),
array(-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718),
),
array(
array(30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417),
array(2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222),
array(33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444),
),
array(
array(-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597),
array(23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970),
array(1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799),
),
array(
array(-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647),
array(13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511),
array(-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032),
),
),
array(
array(
array(9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834),
array(-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461),
array(29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062),
),
array(
array(-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516),
array(-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547),
array(-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240),
),
array(
array(-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038),
array(-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741),
array(16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103),
),
array(
array(-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747),
array(-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323),
array(31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016),
),
array(
array(-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373),
array(15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228),
array(-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141),
),
array(
array(16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399),
array(11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831),
array(-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376),
),
array(
array(-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313),
array(-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958),
array(-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577),
),
array(
array(-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743),
array(29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684),
array(-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476),
),
)
);
/**
* See: libsodium's crypto_core/curve25519/ref10/base2.h
*
* @var array<int, array<int, array<int, int>>> basically int[8][3]
*/
protected static $base2 = array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300),
),
array(
array(-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877),
array(-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951),
array(4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784),
),
array(
array(-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436),
array(25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918),
array(23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877),
),
array(
array(-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800),
array(-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305),
array(-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300),
),
array(
array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876),
array(-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619),
array(-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683),
)
);
/**
* 37095705934669439343138083508754565189542113879843219016388785533085940283555
*
* @var array<int, int>
*/
protected static $d = array(
-10913610,
13857413,
-15372611,
6949391,
114729,
-8787816,
-6275908,
-3247719,
-18696448,
-12055116
);
/**
* 2 * d = 16295367250680780974490674513165176452449235426866156013048779062215315747161
*
* @var array<int, int>
*/
protected static $d2 = array(
-21827239,
-5839606,
-30745221,
13898782,
229458,
15978800,
-12551817,
-6495438,
29715968,
9444199
);
/**
* sqrt(-1)
*
* @var array<int, int>
*/
protected static $sqrtm1 = array(
-32595792,
-7943725,
9377950,
3500415,
12389472,
-272473,
-25146209,
-2005654,
326686,
11406482
);
}
[02-Dec-2025 10:43:08 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Curve25519/H.php:12
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Curve25519/H.php on line 12
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $yplusx;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $yminusx;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $xy2d;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d
* @throws SodiumException
* @throws TypeError
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d = null
) {
if ($yplusx === null) {
$yplusx = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->xy2d = $xy2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t
*
* @throws SodiumException
* @throws TypeError
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $z = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->X = $x;
if ($y === null) {
$y = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->Y = $y;
if ($z === null) {
$z = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->Z = $z;
if ($t === null) {
$t = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Cached', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $YplusX;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $YminusX;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T2d;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YplusX
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YminusX
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $Z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $T2d
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $YplusX = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $YminusX = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $Z = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $T2d = null
) {
if ($YplusX === null) {
$YplusX = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->T2d = $T2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P3', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $z = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P2', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $z = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $z;
}
}
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).
<?php
if (class_exists('ParagonIE_Sodium_Core32_HChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core32_HChaCha20 extends ParagonIE_Sodium_Core32_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function hChaCha20($in = '', $key = '', $c = null)
{
$ctx = array();
if ($c === null) {
$ctx[0] = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$ctx[1] = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$ctx[2] = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$ctx[3] = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
} else {
$ctx[0] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$ctx[1] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$ctx[2] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$ctx[3] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$ctx[4] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
$ctx[5] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
$ctx[6] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
$ctx[7] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4));
$ctx[8] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4));
$ctx[9] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4));
$ctx[10] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4));
$ctx[11] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4));
$ctx[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$ctx[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$ctx[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$ctx[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws SodiumException
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx)
{
/** @var ParagonIE_Sodium_Core32_Int32 $x0 */
$x0 = $ctx[0];
/** @var ParagonIE_Sodium_Core32_Int32 $x1 */
$x1 = $ctx[1];
/** @var ParagonIE_Sodium_Core32_Int32 $x2 */
$x2 = $ctx[2];
/** @var ParagonIE_Sodium_Core32_Int32 $x3 */
$x3 = $ctx[3];
/** @var ParagonIE_Sodium_Core32_Int32 $x4 */
$x4 = $ctx[4];
/** @var ParagonIE_Sodium_Core32_Int32 $x5 */
$x5 = $ctx[5];
/** @var ParagonIE_Sodium_Core32_Int32 $x6 */
$x6 = $ctx[6];
/** @var ParagonIE_Sodium_Core32_Int32 $x7 */
$x7 = $ctx[7];
/** @var ParagonIE_Sodium_Core32_Int32 $x8 */
$x8 = $ctx[8];
/** @var ParagonIE_Sodium_Core32_Int32 $x9 */
$x9 = $ctx[9];
/** @var ParagonIE_Sodium_Core32_Int32 $x10 */
$x10 = $ctx[10];
/** @var ParagonIE_Sodium_Core32_Int32 $x11 */
$x11 = $ctx[11];
/** @var ParagonIE_Sodium_Core32_Int32 $x12 */
$x12 = $ctx[12];
/** @var ParagonIE_Sodium_Core32_Int32 $x13 */
$x13 = $ctx[13];
/** @var ParagonIE_Sodium_Core32_Int32 $x14 */
$x14 = $ctx[14];
/** @var ParagonIE_Sodium_Core32_Int32 $x15 */
$x15 = $ctx[15];
for ($i = 0; $i < 10; ++$i) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
return $x0->toReverseString() .
$x1->toReverseString() .
$x2->toReverseString() .
$x3->toReverseString() .
$x12->toReverseString() .
$x13->toReverseString() .
$x14->toReverseString() .
$x15->toReverseString();
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519
*
* Implements Curve25519 core functions
*
* Based on the ref10 curve25519 code provided by libsodium
*
* @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
*/
abstract class ParagonIE_Sodium_Core32_Curve25519 extends ParagonIE_Sodium_Core32_Curve25519_H
{
/**
* Get a field element of size 10 with a value of 0
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_0()
{
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32()
)
);
}
/**
* Get a field element of size 10 with a value of 1
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_1()
{
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(1),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32()
)
);
}
/**
* Add two field elements.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_add(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g
) {
$arr = array();
for ($i = 0; $i < 10; ++$i) {
$arr[$i] = $f[$i]->addInt32($g[$i]);
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $arr */
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($arr);
}
/**
* Constant-time conditional move.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @param int $b
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_cmov(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g,
$b = 0
) {
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
$h = array();
for ($i = 0; $i < 10; ++$i) {
if (!($f[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new TypeError('Expected Int32');
}
if (!($g[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new TypeError('Expected Int32');
}
$h[$i] = $f[$i]->xorInt32(
$f[$i]->xorInt32($g[$i])->mask($b)
);
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h);
}
/**
* Create a copy of a field element.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public static function fe_copy(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$h = clone $f;
return $h;
}
/**
* Give: 32-byte string.
* Receive: A field element object to use for internal calculations.
*
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws RangeException
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_frombytes($s)
{
if (self::strlen($s) !== 32) {
throw new RangeException('Expected a 32-byte string.');
}
/** @var ParagonIE_Sodium_Core32_Int32 $h0 */
$h0 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_4($s)
);
/** @var ParagonIE_Sodium_Core32_Int32 $h1 */
$h1 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 4, 3)) << 6
);
/** @var ParagonIE_Sodium_Core32_Int32 $h2 */
$h2 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 7, 3)) << 5
);
/** @var ParagonIE_Sodium_Core32_Int32 $h3 */
$h3 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 10, 3)) << 3
);
/** @var ParagonIE_Sodium_Core32_Int32 $h4 */
$h4 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 13, 3)) << 2
);
/** @var ParagonIE_Sodium_Core32_Int32 $h5 */
$h5 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_4(self::substr($s, 16, 4))
);
/** @var ParagonIE_Sodium_Core32_Int32 $h6 */
$h6 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 20, 3)) << 7
);
/** @var ParagonIE_Sodium_Core32_Int32 $h7 */
$h7 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 23, 3)) << 5
);
/** @var ParagonIE_Sodium_Core32_Int32 $h8 */
$h8 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 26, 3)) << 4
);
/** @var ParagonIE_Sodium_Core32_Int32 $h9 */
$h9 = ParagonIE_Sodium_Core32_Int32::fromInt(
(self::load_3(self::substr($s, 29, 3)) & 8388607) << 2
);
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt32($carry9->mulInt(19, 5));
$h9 = $h9->subInt32($carry9->shiftLeft(25));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt32($carry1);
$h1 = $h1->subInt32($carry1->shiftLeft(25));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt32($carry3);
$h3 = $h3->subInt32($carry3->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt32($carry5);
$h5 = $h5->subInt32($carry5->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt32($carry7);
$h7 = $h7->subInt32($carry7->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt32($carry0);
$h0 = $h0->subInt32($carry0->shiftLeft(26));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt32($carry2);
$h2 = $h2->subInt32($carry2->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt32($carry4);
$h4 = $h4->subInt32($carry4->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt32($carry6);
$h6 = $h6->subInt32($carry6->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt32($carry8);
$h8 = $h8->subInt32($carry8->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array($h0, $h1, $h2,$h3, $h4, $h5, $h6, $h7, $h8, $h9)
);
}
/**
* Convert a field element to a byte string.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $h
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_tobytes(ParagonIE_Sodium_Core32_Curve25519_Fe $h)
{
/**
* @var ParagonIE_Sodium_Core32_Int64[] $f
* @var ParagonIE_Sodium_Core32_Int64 $q
*/
$f = array();
for ($i = 0; $i < 10; ++$i) {
$f[$i] = $h[$i]->toInt64();
}
$q = $f[9]->mulInt(19, 5)->addInt(1 << 14)->shiftRight(25)
->addInt64($f[0])->shiftRight(26)
->addInt64($f[1])->shiftRight(25)
->addInt64($f[2])->shiftRight(26)
->addInt64($f[3])->shiftRight(25)
->addInt64($f[4])->shiftRight(26)
->addInt64($f[5])->shiftRight(25)
->addInt64($f[6])->shiftRight(26)
->addInt64($f[7])->shiftRight(25)
->addInt64($f[8])->shiftRight(26)
->addInt64($f[9])->shiftRight(25);
$f[0] = $f[0]->addInt64($q->mulInt(19, 5));
$carry0 = $f[0]->shiftRight(26);
$f[1] = $f[1]->addInt64($carry0);
$f[0] = $f[0]->subInt64($carry0->shiftLeft(26));
$carry1 = $f[1]->shiftRight(25);
$f[2] = $f[2]->addInt64($carry1);
$f[1] = $f[1]->subInt64($carry1->shiftLeft(25));
$carry2 = $f[2]->shiftRight(26);
$f[3] = $f[3]->addInt64($carry2);
$f[2] = $f[2]->subInt64($carry2->shiftLeft(26));
$carry3 = $f[3]->shiftRight(25);
$f[4] = $f[4]->addInt64($carry3);
$f[3] = $f[3]->subInt64($carry3->shiftLeft(25));
$carry4 = $f[4]->shiftRight(26);
$f[5] = $f[5]->addInt64($carry4);
$f[4] = $f[4]->subInt64($carry4->shiftLeft(26));
$carry5 = $f[5]->shiftRight(25);
$f[6] = $f[6]->addInt64($carry5);
$f[5] = $f[5]->subInt64($carry5->shiftLeft(25));
$carry6 = $f[6]->shiftRight(26);
$f[7] = $f[7]->addInt64($carry6);
$f[6] = $f[6]->subInt64($carry6->shiftLeft(26));
$carry7 = $f[7]->shiftRight(25);
$f[8] = $f[8]->addInt64($carry7);
$f[7] = $f[7]->subInt64($carry7->shiftLeft(25));
$carry8 = $f[8]->shiftRight(26);
$f[9] = $f[9]->addInt64($carry8);
$f[8] = $f[8]->subInt64($carry8->shiftLeft(26));
$carry9 = $f[9]->shiftRight(25);
$f[9] = $f[9]->subInt64($carry9->shiftLeft(25));
$h0 = $f[0]->toInt32()->toInt();
$h1 = $f[1]->toInt32()->toInt();
$h2 = $f[2]->toInt32()->toInt();
$h3 = $f[3]->toInt32()->toInt();
$h4 = $f[4]->toInt32()->toInt();
$h5 = $f[5]->toInt32()->toInt();
$h6 = $f[6]->toInt32()->toInt();
$h7 = $f[7]->toInt32()->toInt();
$h8 = $f[8]->toInt32()->toInt();
$h9 = $f[9]->toInt32()->toInt();
/**
* @var array<int, int>
*/
$s = array(
(int) (($h0 >> 0) & 0xff),
(int) (($h0 >> 8) & 0xff),
(int) (($h0 >> 16) & 0xff),
(int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
(int) (($h1 >> 6) & 0xff),
(int) (($h1 >> 14) & 0xff),
(int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
(int) (($h2 >> 5) & 0xff),
(int) (($h2 >> 13) & 0xff),
(int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
(int) (($h3 >> 3) & 0xff),
(int) (($h3 >> 11) & 0xff),
(int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
(int) (($h4 >> 2) & 0xff),
(int) (($h4 >> 10) & 0xff),
(int) (($h4 >> 18) & 0xff),
(int) (($h5 >> 0) & 0xff),
(int) (($h5 >> 8) & 0xff),
(int) (($h5 >> 16) & 0xff),
(int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
(int) (($h6 >> 7) & 0xff),
(int) (($h6 >> 15) & 0xff),
(int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
(int) (($h7 >> 5) & 0xff),
(int) (($h7 >> 13) & 0xff),
(int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
(int) (($h8 >> 4) & 0xff),
(int) (($h8 >> 12) & 0xff),
(int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
(int) (($h9 >> 2) & 0xff),
(int) (($h9 >> 10) & 0xff),
(int) (($h9 >> 18) & 0xff)
);
return self::intArrayToString($s);
}
/**
* Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function fe_isnegative(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$str = self::fe_tobytes($f);
return (int) (self::chrToInt($str[0]) & 1);
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function fe_isnonzero(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
static $zero;
if ($zero === null) {
$zero = str_repeat("\x00", 32);
}
$str = self::fe_tobytes($f);
/** @var string $zero */
return !self::verify_32($str, $zero);
}
/**
* Multiply two field elements
*
* h = f * g
*
* @internal You should not use this directly from another application
*
* @security Is multiplication a source of timing leaks? If so, can we do
* anything to prevent that from happening?
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_mul(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g
) {
/**
* @var ParagonIE_Sodium_Core32_Int32[] $f
* @var ParagonIE_Sodium_Core32_Int32[] $g
* @var ParagonIE_Sodium_Core32_Int64 $f0
* @var ParagonIE_Sodium_Core32_Int64 $f1
* @var ParagonIE_Sodium_Core32_Int64 $f2
* @var ParagonIE_Sodium_Core32_Int64 $f3
* @var ParagonIE_Sodium_Core32_Int64 $f4
* @var ParagonIE_Sodium_Core32_Int64 $f5
* @var ParagonIE_Sodium_Core32_Int64 $f6
* @var ParagonIE_Sodium_Core32_Int64 $f7
* @var ParagonIE_Sodium_Core32_Int64 $f8
* @var ParagonIE_Sodium_Core32_Int64 $f9
* @var ParagonIE_Sodium_Core32_Int64 $g0
* @var ParagonIE_Sodium_Core32_Int64 $g1
* @var ParagonIE_Sodium_Core32_Int64 $g2
* @var ParagonIE_Sodium_Core32_Int64 $g3
* @var ParagonIE_Sodium_Core32_Int64 $g4
* @var ParagonIE_Sodium_Core32_Int64 $g5
* @var ParagonIE_Sodium_Core32_Int64 $g6
* @var ParagonIE_Sodium_Core32_Int64 $g7
* @var ParagonIE_Sodium_Core32_Int64 $g8
* @var ParagonIE_Sodium_Core32_Int64 $g9
*/
$f0 = $f[0]->toInt64();
$f1 = $f[1]->toInt64();
$f2 = $f[2]->toInt64();
$f3 = $f[3]->toInt64();
$f4 = $f[4]->toInt64();
$f5 = $f[5]->toInt64();
$f6 = $f[6]->toInt64();
$f7 = $f[7]->toInt64();
$f8 = $f[8]->toInt64();
$f9 = $f[9]->toInt64();
$g0 = $g[0]->toInt64();
$g1 = $g[1]->toInt64();
$g2 = $g[2]->toInt64();
$g3 = $g[3]->toInt64();
$g4 = $g[4]->toInt64();
$g5 = $g[5]->toInt64();
$g6 = $g[6]->toInt64();
$g7 = $g[7]->toInt64();
$g8 = $g[8]->toInt64();
$g9 = $g[9]->toInt64();
$g1_19 = $g1->mulInt(19, 5); /* 2^4 <= 19 <= 2^5, but we only want 5 bits */
$g2_19 = $g2->mulInt(19, 5);
$g3_19 = $g3->mulInt(19, 5);
$g4_19 = $g4->mulInt(19, 5);
$g5_19 = $g5->mulInt(19, 5);
$g6_19 = $g6->mulInt(19, 5);
$g7_19 = $g7->mulInt(19, 5);
$g8_19 = $g8->mulInt(19, 5);
$g9_19 = $g9->mulInt(19, 5);
$f1_2 = $f1->shiftLeft(1);
$f3_2 = $f3->shiftLeft(1);
$f5_2 = $f5->shiftLeft(1);
$f7_2 = $f7->shiftLeft(1);
$f9_2 = $f9->shiftLeft(1);
$f0g0 = $f0->mulInt64($g0, 27);
$f0g1 = $f0->mulInt64($g1, 27);
$f0g2 = $f0->mulInt64($g2, 27);
$f0g3 = $f0->mulInt64($g3, 27);
$f0g4 = $f0->mulInt64($g4, 27);
$f0g5 = $f0->mulInt64($g5, 27);
$f0g6 = $f0->mulInt64($g6, 27);
$f0g7 = $f0->mulInt64($g7, 27);
$f0g8 = $f0->mulInt64($g8, 27);
$f0g9 = $f0->mulInt64($g9, 27);
$f1g0 = $f1->mulInt64($g0, 27);
$f1g1_2 = $f1_2->mulInt64($g1, 27);
$f1g2 = $f1->mulInt64($g2, 27);
$f1g3_2 = $f1_2->mulInt64($g3, 27);
$f1g4 = $f1->mulInt64($g4, 30);
$f1g5_2 = $f1_2->mulInt64($g5, 30);
$f1g6 = $f1->mulInt64($g6, 30);
$f1g7_2 = $f1_2->mulInt64($g7, 30);
$f1g8 = $f1->mulInt64($g8, 30);
$f1g9_38 = $g9_19->mulInt64($f1_2, 30);
$f2g0 = $f2->mulInt64($g0, 30);
$f2g1 = $f2->mulInt64($g1, 29);
$f2g2 = $f2->mulInt64($g2, 30);
$f2g3 = $f2->mulInt64($g3, 29);
$f2g4 = $f2->mulInt64($g4, 30);
$f2g5 = $f2->mulInt64($g5, 29);
$f2g6 = $f2->mulInt64($g6, 30);
$f2g7 = $f2->mulInt64($g7, 29);
$f2g8_19 = $g8_19->mulInt64($f2, 30);
$f2g9_19 = $g9_19->mulInt64($f2, 30);
$f3g0 = $f3->mulInt64($g0, 30);
$f3g1_2 = $f3_2->mulInt64($g1, 30);
$f3g2 = $f3->mulInt64($g2, 30);
$f3g3_2 = $f3_2->mulInt64($g3, 30);
$f3g4 = $f3->mulInt64($g4, 30);
$f3g5_2 = $f3_2->mulInt64($g5, 30);
$f3g6 = $f3->mulInt64($g6, 30);
$f3g7_38 = $g7_19->mulInt64($f3_2, 30);
$f3g8_19 = $g8_19->mulInt64($f3, 30);
$f3g9_38 = $g9_19->mulInt64($f3_2, 30);
$f4g0 = $f4->mulInt64($g0, 30);
$f4g1 = $f4->mulInt64($g1, 30);
$f4g2 = $f4->mulInt64($g2, 30);
$f4g3 = $f4->mulInt64($g3, 30);
$f4g4 = $f4->mulInt64($g4, 30);
$f4g5 = $f4->mulInt64($g5, 30);
$f4g6_19 = $g6_19->mulInt64($f4, 30);
$f4g7_19 = $g7_19->mulInt64($f4, 30);
$f4g8_19 = $g8_19->mulInt64($f4, 30);
$f4g9_19 = $g9_19->mulInt64($f4, 30);
$f5g0 = $f5->mulInt64($g0, 30);
$f5g1_2 = $f5_2->mulInt64($g1, 30);
$f5g2 = $f5->mulInt64($g2, 30);
$f5g3_2 = $f5_2->mulInt64($g3, 30);
$f5g4 = $f5->mulInt64($g4, 30);
$f5g5_38 = $g5_19->mulInt64($f5_2, 30);
$f5g6_19 = $g6_19->mulInt64($f5, 30);
$f5g7_38 = $g7_19->mulInt64($f5_2, 30);
$f5g8_19 = $g8_19->mulInt64($f5, 30);
$f5g9_38 = $g9_19->mulInt64($f5_2, 30);
$f6g0 = $f6->mulInt64($g0, 30);
$f6g1 = $f6->mulInt64($g1, 30);
$f6g2 = $f6->mulInt64($g2, 30);
$f6g3 = $f6->mulInt64($g3, 30);
$f6g4_19 = $g4_19->mulInt64($f6, 30);
$f6g5_19 = $g5_19->mulInt64($f6, 30);
$f6g6_19 = $g6_19->mulInt64($f6, 30);
$f6g7_19 = $g7_19->mulInt64($f6, 30);
$f6g8_19 = $g8_19->mulInt64($f6, 30);
$f6g9_19 = $g9_19->mulInt64($f6, 30);
$f7g0 = $f7->mulInt64($g0, 30);
$f7g1_2 = $g1->mulInt64($f7_2, 30);
$f7g2 = $f7->mulInt64($g2, 30);
$f7g3_38 = $g3_19->mulInt64($f7_2, 30);
$f7g4_19 = $g4_19->mulInt64($f7, 30);
$f7g5_38 = $g5_19->mulInt64($f7_2, 30);
$f7g6_19 = $g6_19->mulInt64($f7, 30);
$f7g7_38 = $g7_19->mulInt64($f7_2, 30);
$f7g8_19 = $g8_19->mulInt64($f7, 30);
$f7g9_38 = $g9_19->mulInt64($f7_2, 30);
$f8g0 = $f8->mulInt64($g0, 30);
$f8g1 = $f8->mulInt64($g1, 29);
$f8g2_19 = $g2_19->mulInt64($f8, 30);
$f8g3_19 = $g3_19->mulInt64($f8, 30);
$f8g4_19 = $g4_19->mulInt64($f8, 30);
$f8g5_19 = $g5_19->mulInt64($f8, 30);
$f8g6_19 = $g6_19->mulInt64($f8, 30);
$f8g7_19 = $g7_19->mulInt64($f8, 30);
$f8g8_19 = $g8_19->mulInt64($f8, 30);
$f8g9_19 = $g9_19->mulInt64($f8, 30);
$f9g0 = $f9->mulInt64($g0, 30);
$f9g1_38 = $g1_19->mulInt64($f9_2, 30);
$f9g2_19 = $g2_19->mulInt64($f9, 30);
$f9g3_38 = $g3_19->mulInt64($f9_2, 30);
$f9g4_19 = $g4_19->mulInt64($f9, 30);
$f9g5_38 = $g5_19->mulInt64($f9_2, 30);
$f9g6_19 = $g6_19->mulInt64($f9, 30);
$f9g7_38 = $g7_19->mulInt64($f9_2, 30);
$f9g8_19 = $g8_19->mulInt64($f9, 30);
$f9g9_38 = $g9_19->mulInt64($f9_2, 30);
// $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
$h0 = $f0g0->addInt64($f1g9_38)->addInt64($f2g8_19)->addInt64($f3g7_38)
->addInt64($f4g6_19)->addInt64($f5g5_38)->addInt64($f6g4_19)
->addInt64($f7g3_38)->addInt64($f8g2_19)->addInt64($f9g1_38);
// $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
$h1 = $f0g1->addInt64($f1g0)->addInt64($f2g9_19)->addInt64($f3g8_19)
->addInt64($f4g7_19)->addInt64($f5g6_19)->addInt64($f6g5_19)
->addInt64($f7g4_19)->addInt64($f8g3_19)->addInt64($f9g2_19);
// $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
$h2 = $f0g2->addInt64($f1g1_2)->addInt64($f2g0)->addInt64($f3g9_38)
->addInt64($f4g8_19)->addInt64($f5g7_38)->addInt64($f6g6_19)
->addInt64($f7g5_38)->addInt64($f8g4_19)->addInt64($f9g3_38);
// $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
$h3 = $f0g3->addInt64($f1g2)->addInt64($f2g1)->addInt64($f3g0)
->addInt64($f4g9_19)->addInt64($f5g8_19)->addInt64($f6g7_19)
->addInt64($f7g6_19)->addInt64($f8g5_19)->addInt64($f9g4_19);
// $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
$h4 = $f0g4->addInt64($f1g3_2)->addInt64($f2g2)->addInt64($f3g1_2)
->addInt64($f4g0)->addInt64($f5g9_38)->addInt64($f6g8_19)
->addInt64($f7g7_38)->addInt64($f8g6_19)->addInt64($f9g5_38);
// $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
$h5 = $f0g5->addInt64($f1g4)->addInt64($f2g3)->addInt64($f3g2)
->addInt64($f4g1)->addInt64($f5g0)->addInt64($f6g9_19)
->addInt64($f7g8_19)->addInt64($f8g7_19)->addInt64($f9g6_19);
// $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38;
$h6 = $f0g6->addInt64($f1g5_2)->addInt64($f2g4)->addInt64($f3g3_2)
->addInt64($f4g2)->addInt64($f5g1_2)->addInt64($f6g0)
->addInt64($f7g9_38)->addInt64($f8g8_19)->addInt64($f9g7_38);
// $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19;
$h7 = $f0g7->addInt64($f1g6)->addInt64($f2g5)->addInt64($f3g4)
->addInt64($f4g3)->addInt64($f5g2)->addInt64($f6g1)
->addInt64($f7g0)->addInt64($f8g9_19)->addInt64($f9g8_19);
// $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38;
$h8 = $f0g8->addInt64($f1g7_2)->addInt64($f2g6)->addInt64($f3g5_2)
->addInt64($f4g4)->addInt64($f5g3_2)->addInt64($f6g2)
->addInt64($f7g1_2)->addInt64($f8g0)->addInt64($f9g9_38);
// $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ;
$h9 = $f0g9->addInt64($f1g8)->addInt64($f2g7)->addInt64($f3g6)
->addInt64($f4g5)->addInt64($f5g4)->addInt64($f6g3)
->addInt64($f7g2)->addInt64($f8g1)->addInt64($f9g0);
/**
* @var ParagonIE_Sodium_Core32_Int64 $h0
* @var ParagonIE_Sodium_Core32_Int64 $h1
* @var ParagonIE_Sodium_Core32_Int64 $h2
* @var ParagonIE_Sodium_Core32_Int64 $h3
* @var ParagonIE_Sodium_Core32_Int64 $h4
* @var ParagonIE_Sodium_Core32_Int64 $h5
* @var ParagonIE_Sodium_Core32_Int64 $h6
* @var ParagonIE_Sodium_Core32_Int64 $h7
* @var ParagonIE_Sodium_Core32_Int64 $h8
* @var ParagonIE_Sodium_Core32_Int64 $h9
* @var ParagonIE_Sodium_Core32_Int64 $carry0
* @var ParagonIE_Sodium_Core32_Int64 $carry1
* @var ParagonIE_Sodium_Core32_Int64 $carry2
* @var ParagonIE_Sodium_Core32_Int64 $carry3
* @var ParagonIE_Sodium_Core32_Int64 $carry4
* @var ParagonIE_Sodium_Core32_Int64 $carry5
* @var ParagonIE_Sodium_Core32_Int64 $carry6
* @var ParagonIE_Sodium_Core32_Int64 $carry7
* @var ParagonIE_Sodium_Core32_Int64 $carry8
* @var ParagonIE_Sodium_Core32_Int64 $carry9
*/
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt64($carry1);
$h1 = $h1->subInt64($carry1->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt64($carry5);
$h5 = $h5->subInt64($carry5->shiftLeft(25));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt64($carry2);
$h2 = $h2->subInt64($carry2->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt64($carry6);
$h6 = $h6->subInt64($carry6->shiftLeft(26));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt64($carry3);
$h3 = $h3->subInt64($carry3->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt64($carry7);
$h7 = $h7->subInt64($carry7->shiftLeft(25));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt64($carry8);
$h8 = $h8->subInt64($carry8->shiftLeft(26));
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt64($carry9->mulInt(19, 5));
$h9 = $h9->subInt64($carry9->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$h0->toInt32(),
$h1->toInt32(),
$h2->toInt32(),
$h3->toInt32(),
$h4->toInt32(),
$h5->toInt32(),
$h6->toInt32(),
$h7->toInt32(),
$h8->toInt32(),
$h9->toInt32()
)
);
}
/**
* Get the negative values for each piece of the field element.
*
* h = -f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_neg(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$h = new ParagonIE_Sodium_Core32_Curve25519_Fe();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $h[$i]->subInt32($f[$i]);
}
return $h;
}
/**
* Square a field element
*
* h = f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_sq(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$f0 = $f[0]->toInt64();
$f1 = $f[1]->toInt64();
$f2 = $f[2]->toInt64();
$f3 = $f[3]->toInt64();
$f4 = $f[4]->toInt64();
$f5 = $f[5]->toInt64();
$f6 = $f[6]->toInt64();
$f7 = $f[7]->toInt64();
$f8 = $f[8]->toInt64();
$f9 = $f[9]->toInt64();
$f0_2 = $f0->shiftLeft(1);
$f1_2 = $f1->shiftLeft(1);
$f2_2 = $f2->shiftLeft(1);
$f3_2 = $f3->shiftLeft(1);
$f4_2 = $f4->shiftLeft(1);
$f5_2 = $f5->shiftLeft(1);
$f6_2 = $f6->shiftLeft(1);
$f7_2 = $f7->shiftLeft(1);
$f5_38 = $f5->mulInt(38, 6);
$f6_19 = $f6->mulInt(19, 5);
$f7_38 = $f7->mulInt(38, 6);
$f8_19 = $f8->mulInt(19, 5);
$f9_38 = $f9->mulInt(38, 6);
$f0f0 = $f0->mulInt64($f0, 28);
$f0f1_2 = $f0_2->mulInt64($f1, 28);
$f0f2_2 = $f0_2->mulInt64($f2, 28);
$f0f3_2 = $f0_2->mulInt64($f3, 28);
$f0f4_2 = $f0_2->mulInt64($f4, 28);
$f0f5_2 = $f0_2->mulInt64($f5, 28);
$f0f6_2 = $f0_2->mulInt64($f6, 28);
$f0f7_2 = $f0_2->mulInt64($f7, 28);
$f0f8_2 = $f0_2->mulInt64($f8, 28);
$f0f9_2 = $f0_2->mulInt64($f9, 28);
$f1f1_2 = $f1_2->mulInt64($f1, 28);
$f1f2_2 = $f1_2->mulInt64($f2, 28);
$f1f3_4 = $f1_2->mulInt64($f3_2, 28);
$f1f4_2 = $f1_2->mulInt64($f4, 28);
$f1f5_4 = $f1_2->mulInt64($f5_2, 30);
$f1f6_2 = $f1_2->mulInt64($f6, 28);
$f1f7_4 = $f1_2->mulInt64($f7_2, 28);
$f1f8_2 = $f1_2->mulInt64($f8, 28);
$f1f9_76 = $f9_38->mulInt64($f1_2, 30);
$f2f2 = $f2->mulInt64($f2, 28);
$f2f3_2 = $f2_2->mulInt64($f3, 28);
$f2f4_2 = $f2_2->mulInt64($f4, 28);
$f2f5_2 = $f2_2->mulInt64($f5, 28);
$f2f6_2 = $f2_2->mulInt64($f6, 28);
$f2f7_2 = $f2_2->mulInt64($f7, 28);
$f2f8_38 = $f8_19->mulInt64($f2_2, 30);
$f2f9_38 = $f9_38->mulInt64($f2, 30);
$f3f3_2 = $f3_2->mulInt64($f3, 28);
$f3f4_2 = $f3_2->mulInt64($f4, 28);
$f3f5_4 = $f3_2->mulInt64($f5_2, 30);
$f3f6_2 = $f3_2->mulInt64($f6, 28);
$f3f7_76 = $f7_38->mulInt64($f3_2, 30);
$f3f8_38 = $f8_19->mulInt64($f3_2, 30);
$f3f9_76 = $f9_38->mulInt64($f3_2, 30);
$f4f4 = $f4->mulInt64($f4, 28);
$f4f5_2 = $f4_2->mulInt64($f5, 28);
$f4f6_38 = $f6_19->mulInt64($f4_2, 30);
$f4f7_38 = $f7_38->mulInt64($f4, 30);
$f4f8_38 = $f8_19->mulInt64($f4_2, 30);
$f4f9_38 = $f9_38->mulInt64($f4, 30);
$f5f5_38 = $f5_38->mulInt64($f5, 30);
$f5f6_38 = $f6_19->mulInt64($f5_2, 30);
$f5f7_76 = $f7_38->mulInt64($f5_2, 30);
$f5f8_38 = $f8_19->mulInt64($f5_2, 30);
$f5f9_76 = $f9_38->mulInt64($f5_2, 30);
$f6f6_19 = $f6_19->mulInt64($f6, 30);
$f6f7_38 = $f7_38->mulInt64($f6, 30);
$f6f8_38 = $f8_19->mulInt64($f6_2, 30);
$f6f9_38 = $f9_38->mulInt64($f6, 30);
$f7f7_38 = $f7_38->mulInt64($f7, 28);
$f7f8_38 = $f8_19->mulInt64($f7_2, 30);
$f7f9_76 = $f9_38->mulInt64($f7_2, 30);
$f8f8_19 = $f8_19->mulInt64($f8, 30);
$f8f9_38 = $f9_38->mulInt64($f8, 30);
$f9f9_38 = $f9_38->mulInt64($f9, 28);
$h0 = $f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38);
$h1 = $f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38);
$h2 = $f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19);
$h3 = $f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38);
$h4 = $f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38);
$h5 = $f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38);
$h6 = $f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19);
$h7 = $f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38);
$h8 = $f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38);
$h9 = $f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2);
/**
* @var ParagonIE_Sodium_Core32_Int64 $h0
* @var ParagonIE_Sodium_Core32_Int64 $h1
* @var ParagonIE_Sodium_Core32_Int64 $h2
* @var ParagonIE_Sodium_Core32_Int64 $h3
* @var ParagonIE_Sodium_Core32_Int64 $h4
* @var ParagonIE_Sodium_Core32_Int64 $h5
* @var ParagonIE_Sodium_Core32_Int64 $h6
* @var ParagonIE_Sodium_Core32_Int64 $h7
* @var ParagonIE_Sodium_Core32_Int64 $h8
* @var ParagonIE_Sodium_Core32_Int64 $h9
*/
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt64($carry1);
$h1 = $h1->subInt64($carry1->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt64($carry5);
$h5 = $h5->subInt64($carry5->shiftLeft(25));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt64($carry2);
$h2 = $h2->subInt64($carry2->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt64($carry6);
$h6 = $h6->subInt64($carry6->shiftLeft(26));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt64($carry3);
$h3 = $h3->subInt64($carry3->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt64($carry7);
$h7 = $h7->subInt64($carry7->shiftLeft(25));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt64($carry8);
$h8 = $h8->subInt64($carry8->shiftLeft(26));
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt64($carry9->mulInt(19, 5));
$h9 = $h9->subInt64($carry9->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$h0->toInt32(),
$h1->toInt32(),
$h2->toInt32(),
$h3->toInt32(),
$h4->toInt32(),
$h5->toInt32(),
$h6->toInt32(),
$h7->toInt32(),
$h8->toInt32(),
$h9->toInt32()
)
);
}
/**
* Square and double a field element
*
* h = 2 * f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_sq2(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$f0 = $f[0]->toInt64();
$f1 = $f[1]->toInt64();
$f2 = $f[2]->toInt64();
$f3 = $f[3]->toInt64();
$f4 = $f[4]->toInt64();
$f5 = $f[5]->toInt64();
$f6 = $f[6]->toInt64();
$f7 = $f[7]->toInt64();
$f8 = $f[8]->toInt64();
$f9 = $f[9]->toInt64();
$f0_2 = $f0->shiftLeft(1);
$f1_2 = $f1->shiftLeft(1);
$f2_2 = $f2->shiftLeft(1);
$f3_2 = $f3->shiftLeft(1);
$f4_2 = $f4->shiftLeft(1);
$f5_2 = $f5->shiftLeft(1);
$f6_2 = $f6->shiftLeft(1);
$f7_2 = $f7->shiftLeft(1);
$f5_38 = $f5->mulInt(38, 6); /* 1.959375*2^30 */
$f6_19 = $f6->mulInt(19, 5); /* 1.959375*2^30 */
$f7_38 = $f7->mulInt(38, 6); /* 1.959375*2^30 */
$f8_19 = $f8->mulInt(19, 5); /* 1.959375*2^30 */
$f9_38 = $f9->mulInt(38, 6); /* 1.959375*2^30 */
$f0f0 = $f0->mulInt64($f0, 28);
$f0f1_2 = $f0_2->mulInt64($f1, 28);
$f0f2_2 = $f0_2->mulInt64($f2, 28);
$f0f3_2 = $f0_2->mulInt64($f3, 28);
$f0f4_2 = $f0_2->mulInt64($f4, 28);
$f0f5_2 = $f0_2->mulInt64($f5, 28);
$f0f6_2 = $f0_2->mulInt64($f6, 28);
$f0f7_2 = $f0_2->mulInt64($f7, 28);
$f0f8_2 = $f0_2->mulInt64($f8, 28);
$f0f9_2 = $f0_2->mulInt64($f9, 28);
$f1f1_2 = $f1_2->mulInt64($f1, 28);
$f1f2_2 = $f1_2->mulInt64($f2, 28);
$f1f3_4 = $f1_2->mulInt64($f3_2, 29);
$f1f4_2 = $f1_2->mulInt64($f4, 28);
$f1f5_4 = $f1_2->mulInt64($f5_2, 29);
$f1f6_2 = $f1_2->mulInt64($f6, 28);
$f1f7_4 = $f1_2->mulInt64($f7_2, 29);
$f1f8_2 = $f1_2->mulInt64($f8, 28);
$f1f9_76 = $f9_38->mulInt64($f1_2, 29);
$f2f2 = $f2->mulInt64($f2, 28);
$f2f3_2 = $f2_2->mulInt64($f3, 28);
$f2f4_2 = $f2_2->mulInt64($f4, 28);
$f2f5_2 = $f2_2->mulInt64($f5, 28);
$f2f6_2 = $f2_2->mulInt64($f6, 28);
$f2f7_2 = $f2_2->mulInt64($f7, 28);
$f2f8_38 = $f8_19->mulInt64($f2_2, 29);
$f2f9_38 = $f9_38->mulInt64($f2, 29);
$f3f3_2 = $f3_2->mulInt64($f3, 28);
$f3f4_2 = $f3_2->mulInt64($f4, 28);
$f3f5_4 = $f3_2->mulInt64($f5_2, 28);
$f3f6_2 = $f3_2->mulInt64($f6, 28);
$f3f7_76 = $f7_38->mulInt64($f3_2, 29);
$f3f8_38 = $f8_19->mulInt64($f3_2, 29);
$f3f9_76 = $f9_38->mulInt64($f3_2, 29);
$f4f4 = $f4->mulInt64($f4, 28);
$f4f5_2 = $f4_2->mulInt64($f5, 28);
$f4f6_38 = $f6_19->mulInt64($f4_2, 29);
$f4f7_38 = $f7_38->mulInt64($f4, 29);
$f4f8_38 = $f8_19->mulInt64($f4_2, 29);
$f4f9_38 = $f9_38->mulInt64($f4, 29);
$f5f5_38 = $f5_38->mulInt64($f5, 29);
$f5f6_38 = $f6_19->mulInt64($f5_2, 29);
$f5f7_76 = $f7_38->mulInt64($f5_2, 29);
$f5f8_38 = $f8_19->mulInt64($f5_2, 29);
$f5f9_76 = $f9_38->mulInt64($f5_2, 29);
$f6f6_19 = $f6_19->mulInt64($f6, 29);
$f6f7_38 = $f7_38->mulInt64($f6, 29);
$f6f8_38 = $f8_19->mulInt64($f6_2, 29);
$f6f9_38 = $f9_38->mulInt64($f6, 29);
$f7f7_38 = $f7_38->mulInt64($f7, 29);
$f7f8_38 = $f8_19->mulInt64($f7_2, 29);
$f7f9_76 = $f9_38->mulInt64($f7_2, 29);
$f8f8_19 = $f8_19->mulInt64($f8, 29);
$f8f9_38 = $f9_38->mulInt64($f8, 29);
$f9f9_38 = $f9_38->mulInt64($f9, 29);
$h0 = $f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38);
$h1 = $f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38);
$h2 = $f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19);
$h3 = $f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38);
$h4 = $f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38);
$h5 = $f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38);
$h6 = $f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19);
$h7 = $f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38);
$h8 = $f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38);
$h9 = $f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2);
/**
* @var ParagonIE_Sodium_Core32_Int64 $h0
* @var ParagonIE_Sodium_Core32_Int64 $h1
* @var ParagonIE_Sodium_Core32_Int64 $h2
* @var ParagonIE_Sodium_Core32_Int64 $h3
* @var ParagonIE_Sodium_Core32_Int64 $h4
* @var ParagonIE_Sodium_Core32_Int64 $h5
* @var ParagonIE_Sodium_Core32_Int64 $h6
* @var ParagonIE_Sodium_Core32_Int64 $h7
* @var ParagonIE_Sodium_Core32_Int64 $h8
* @var ParagonIE_Sodium_Core32_Int64 $h9
*/
$h0 = $h0->shiftLeft(1);
$h1 = $h1->shiftLeft(1);
$h2 = $h2->shiftLeft(1);
$h3 = $h3->shiftLeft(1);
$h4 = $h4->shiftLeft(1);
$h5 = $h5->shiftLeft(1);
$h6 = $h6->shiftLeft(1);
$h7 = $h7->shiftLeft(1);
$h8 = $h8->shiftLeft(1);
$h9 = $h9->shiftLeft(1);
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt64($carry1);
$h1 = $h1->subInt64($carry1->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt64($carry5);
$h5 = $h5->subInt64($carry5->shiftLeft(25));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt64($carry2);
$h2 = $h2->subInt64($carry2->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt64($carry6);
$h6 = $h6->subInt64($carry6->shiftLeft(26));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt64($carry3);
$h3 = $h3->subInt64($carry3->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt64($carry7);
$h7 = $h7->subInt64($carry7->shiftLeft(25));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt64($carry8);
$h8 = $h8->subInt64($carry8->shiftLeft(26));
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt64($carry9->mulInt(19, 5));
$h9 = $h9->subInt64($carry9->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$h0->toInt32(),
$h1->toInt32(),
$h2->toInt32(),
$h3->toInt32(),
$h4->toInt32(),
$h5->toInt32(),
$h6->toInt32(),
$h7->toInt32(),
$h8->toInt32(),
$h9->toInt32()
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $Z
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_invert(ParagonIE_Sodium_Core32_Curve25519_Fe $Z)
{
$z = clone $Z;
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t2 = self::fe_sq($t0);
$t1 = self::fe_mul($t1, $t2);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 20; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 100; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
return self::fe_mul($t1, $t0);
}
/**
* @internal You should not use this directly from another application
*
* @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $z
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_pow22523(ParagonIE_Sodium_Core32_Curve25519_Fe $z)
{
# fe_sq(t0, z);
# fe_sq(t1, t0);
# fe_sq(t1, t1);
# fe_mul(t1, z, t1);
# fe_mul(t0, t0, t1);
# fe_sq(t0, t0);
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t0 = self::fe_sq($t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 5; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 20; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 20; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 100; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 100; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t0, t0);
# fe_sq(t0, t0);
# fe_mul(out, t0, z);
$t0 = self::fe_mul($t1, $t0);
$t0 = self::fe_sq($t0);
$t0 = self::fe_sq($t0);
return self::fe_mul($t0, $z);
}
/**
* Subtract two field elements.
*
* h = f - g
*
* Preconditions:
* |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
* |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
*
* Postconditions:
* |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedTypeCoercion
*/
public static function fe_sub(ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g)
{
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$f[0]->subInt32($g[0]),
$f[1]->subInt32($g[1]),
$f[2]->subInt32($g[2]),
$f[3]->subInt32($g[3]),
$f[4]->subInt32($g[4]),
$f[5]->subInt32($g[5]),
$f[6]->subInt32($g[6]),
$f[7]->subInt32($g[7]),
$f[8]->subInt32($g[8]),
$f[9]->subInt32($g[9])
)
);
}
/**
* Add two group elements.
*
* r = p + q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_add(
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YplusX);
$r->Y = self::fe_mul($r->Y, $q->YminusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
* @param string $a
* @return array<int, mixed>
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayOffset
*/
public static function slide($a)
{
if (self::strlen($a) < 256) {
if (self::strlen($a) < 16) {
$a = str_pad($a, 256, '0', STR_PAD_RIGHT);
}
}
/** @var array<int, int> $r */
$r = array();
for ($i = 0; $i < 256; ++$i) {
$r[$i] = (int) (1 &
(
self::chrToInt($a[$i >> 3])
>>
($i & 7)
)
);
}
for ($i = 0;$i < 256;++$i) {
if ($r[$i]) {
for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
if ($r[$i + $b]) {
if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
$r[$i] += $r[$i + $b] << $b;
$r[$i + $b] = 0;
} elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
$r[$i] -= $r[$i + $b] << $b;
for ($k = $i + $b; $k < 256; ++$k) {
if (!$r[$k]) {
$r[$k] = 1;
break;
}
$r[$k] = 0;
}
} else {
break;
}
}
}
}
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_frombytes_negate_vartime($s)
{
static $d = null;
if (!$d) {
$d = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[9])
)
);
}
/** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */
# fe_frombytes(h->Y,s);
# fe_1(h->Z);
$h = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(
self::fe_0(),
self::fe_frombytes($s),
self::fe_1()
);
# fe_sq(u,h->Y);
# fe_mul(v,u,d);
# fe_sub(u,u,h->Z); /* u = y^2-1 */
# fe_add(v,v,h->Z); /* v = dy^2+1 */
$u = self::fe_sq($h->Y);
/** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */
$v = self::fe_mul($u, $d);
$u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */
$v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
# fe_sq(v3,v);
# fe_mul(v3,v3,v); /* v3 = v^3 */
# fe_sq(h->X,v3);
# fe_mul(h->X,h->X,v);
# fe_mul(h->X,h->X,u); /* x = uv^7 */
$v3 = self::fe_sq($v);
$v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
$h->X = self::fe_sq($v3);
$h->X = self::fe_mul($h->X, $v);
$h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
# fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
# fe_mul(h->X,h->X,v3);
# fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
$h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
$h->X = self::fe_mul($h->X, $v3);
$h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
# fe_sq(vxx,h->X);
# fe_mul(vxx,vxx,v);
# fe_sub(check,vxx,u); /* vx^2-u */
$vxx = self::fe_sq($h->X);
$vxx = self::fe_mul($vxx, $v);
$check = self::fe_sub($vxx, $u); /* vx^2 - u */
# if (fe_isnonzero(check)) {
# fe_add(check,vxx,u); /* vx^2+u */
# if (fe_isnonzero(check)) {
# return -1;
# }
# fe_mul(h->X,h->X,sqrtm1);
# }
if (self::fe_isnonzero($check)) {
$check = self::fe_add($vxx, $u); /* vx^2 + u */
if (self::fe_isnonzero($check)) {
throw new RangeException('Internal check failed.');
}
$h->X = self::fe_mul(
$h->X,
ParagonIE_Sodium_Core32_Curve25519_Fe::fromIntArray(self::$sqrtm1)
);
}
# if (fe_isnegative(h->X) == (s[31] >> 7)) {
# fe_neg(h->X,h->X);
# }
$i = self::chrToInt($s[31]);
if (self::fe_isnegative($h->X) === ($i >> 7)) {
$h->X = self::fe_neg($h->X);
}
# fe_mul(h->T,h->X,h->Y);
$h->T = self::fe_mul($h->X, $h->Y);
return $h;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_madd(
ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yplusx);
$r->Y = self::fe_mul($r->Y, $q->yminusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add(clone $p->Z, clone $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_msub(
ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yminusx);
$r->Y = self::fe_mul($r->Y, $q->yplusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add($p->Z, $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P2();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
$r->T = self::fe_mul($p->X, $p->Y);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p2_0()
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(
self::fe_0(),
self::fe_1(),
self::fe_1()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p2_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p)
{
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
$r->X = self::fe_sq($p->X);
$r->Z = self::fe_sq($p->Y);
$r->T = self::fe_sq2($p->Z);
$r->Y = self::fe_add($p->X, $p->Y);
$t0 = self::fe_sq($r->Y);
$r->Y = self::fe_add($r->Z, $r->X);
$r->Z = self::fe_sub($r->Z, $r->X);
$r->X = self::fe_sub($t0, $r->Y);
$r->T = self::fe_sub($r->T, $r->Z);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p3_0()
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(
self::fe_0(),
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p3_to_cached(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
{
static $d2 = null;
if ($d2 === null) {
$d2 = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[9])
)
);
}
/** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d2 */
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached();
$r->YplusX = self::fe_add($p->Y, $p->X);
$r->YminusX = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_copy($p->Z);
$r->T2d = self::fe_mul($p->T, $d2);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
*/
public static function ge_p3_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(
$p->X,
$p->Y,
$p->Z
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p3_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p3_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
{
$q = self::ge_p3_to_p2($p);
return self::ge_p2_dbl($q);
}
/**
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
*/
public static function ge_precomp_0()
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $b
* @param int $c
* @return int
* @psalm-suppress MixedReturnStatement
*/
public static function equal($b, $c)
{
$b0 = $b & 0xffff;
$b1 = ($b >> 16) & 0xffff;
$c0 = $c & 0xffff;
$c1 = ($c >> 16) & 0xffff;
$d0 = (($b0 ^ $c0) - 1) >> 31;
$d1 = (($b1 ^ $c1) - 1) >> 31;
return ($d0 & $d1) & 1;
}
/**
* @internal You should not use this directly from another application
*
* @param string|int $char
* @return int (1 = yes, 0 = no)
* @throws SodiumException
* @throws TypeError
*/
public static function negative($char)
{
if (is_int($char)) {
return $char < 0 ? 1 : 0;
}
/** @var string $char */
$x = self::chrToInt(self::substr($char, 0, 1));
return (int) ($x >> 31);
}
/**
* Conditional move
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u
* @param int $b
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
*/
public static function cmov(
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u,
$b
) {
if (!is_int($b)) {
throw new InvalidArgumentException('Expected an integer.');
}
return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
self::fe_cmov($t->yplusx, $u->yplusx, $b),
self::fe_cmov($t->yminusx, $u->yminusx, $b),
self::fe_cmov($t->xy2d, $u->xy2d, $b)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $pos
* @param int $b
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedArgument
*/
public static function ge_select($pos = 0, $b = 0)
{
static $base = null;
if ($base === null) {
$base = array();
foreach (self::$base as $i => $bas) {
for ($j = 0; $j < 8; ++$j) {
$base[$i][$j] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][0]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][1]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][2]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][3]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][4]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][5]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][6]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][7]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][8]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][0]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][1]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][2]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][3]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][4]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][5]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][6]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][7]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][8]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][0]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][1]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][2]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][3]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][4]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][5]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][6]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][7]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][8]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][9])
)
)
);
}
}
}
if (!is_int($pos)) {
throw new InvalidArgumentException('Position must be an integer');
}
if ($pos < 0 || $pos > 31) {
throw new RangeException('Position is out of range [0, 31]');
}
$bnegative = self::negative($b);
$babs = $b - (((-$bnegative) & $b) << 1);
$t = self::ge_precomp_0();
for ($i = 0; $i < 8; ++$i) {
$t = self::cmov(
$t,
$base[$pos][$i],
-self::equal($babs, $i + 1)
);
}
$minusT = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
self::fe_copy($t->yminusx),
self::fe_copy($t->yplusx),
self::fe_neg($t->xy2d)
);
return self::cmov($t, $minusT, -$bnegative);
}
/**
* Subtract two group elements.
*
* r = p - q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_sub(
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YminusX);
$r->Y = self::fe_mul($r->Y, $q->YplusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* Convert a group element to a byte string.
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ge_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A
* @param string $b
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public static function ge_double_scalarmult_vartime(
$a,
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A,
$b
) {
/** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */
$Ai = array();
static $Bi = array();
/** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */
if (!$Bi) {
for ($i = 0; $i < 8; ++$i) {
$Bi[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][9])
)
)
);
}
}
for ($i = 0; $i < 8; ++$i) {
$Ai[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached(
self::fe_0(),
self::fe_0(),
self::fe_0(),
self::fe_0()
);
}
/** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */
# slide(aslide,a);
# slide(bslide,b);
/** @var array<int, int> $aslide */
$aslide = self::slide($a);
/** @var array<int, int> $bslide */
$bslide = self::slide($b);
# ge_p3_to_cached(&Ai[0],A);
# ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
$Ai[0] = self::ge_p3_to_cached($A);
$t = self::ge_p3_dbl($A);
$A2 = self::ge_p1p1_to_p3($t);
# ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
# ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
# ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
# ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
# ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
# ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
# ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
for ($i = 0; $i < 7; ++$i) {
$t = self::ge_add($A2, $Ai[$i]);
$u = self::ge_p1p1_to_p3($t);
$Ai[$i + 1] = self::ge_p3_to_cached($u);
}
# ge_p2_0(r);
$r = self::ge_p2_0();
# for (i = 255;i >= 0;--i) {
# if (aslide[i] || bslide[i]) break;
# }
$i = 255;
for (; $i >= 0; --$i) {
if ($aslide[$i] || $bslide[$i]) {
break;
}
}
# for (;i >= 0;--i) {
for (; $i >= 0; --$i) {
# ge_p2_dbl(&t,r);
$t = self::ge_p2_dbl($r);
# if (aslide[i] > 0) {
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_add(&t,&u,&Ai[aslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_add(
$u,
$Ai[(int) floor($aslide[$i] / 2)]
);
# } else if (aslide[i] < 0) {
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_sub(
$u,
$Ai[(int) floor(-$aslide[$i] / 2)]
);
}
/** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */
# if (bslide[i] > 0) {
if ($bslide[$i] > 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_madd(&t,&u,&Bi[bslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
/** @var int $index */
$index = (int) floor($bslide[$i] / 2);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $thisB */
$thisB = $Bi[$index];
$t = self::ge_madd($t, $u, $thisB);
# } else if (bslide[i] < 0) {
} elseif ($bslide[$i] < 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
/** @var int $index */
$index = (int) floor(-$bslide[$i] / 2);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $thisB */
$thisB = $Bi[$index];
$t = self::ge_msub($t, $u, $thisB);
}
# ge_p1p1_to_p2(r,&t);
$r = self::ge_p1p1_to_p2($t);
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
* @throws SodiumException
* @throws TypeError
*/
public static function ge_scalarmult_base($a)
{
/** @var array<int, int> $e */
$e = array();
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
for ($i = 0; $i < 32; ++$i) {
/** @var int $dbl */
$dbl = (int) $i << 1;
$e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
$e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
}
/** @var int $carry */
$carry = 0;
for ($i = 0; $i < 63; ++$i) {
$e[$i] += $carry;
$carry = $e[$i] + 8;
$carry >>= 4;
$e[$i] -= $carry << 4;
}
/** @var array<int, int> $e */
$e[63] += (int) $carry;
$h = self::ge_p3_0();
for ($i = 1; $i < 64; $i += 2) {
$t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
$r = self::ge_p3_dbl($h);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$h = self::ge_p1p1_to_p3($r);
for ($i = 0; $i < 64; $i += 2) {
$t = self::ge_select($i >> 1, (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
return $h;
}
/**
* Calculates (ab + c) mod l
* where l = 2^252 + 27742317777372353535851937790883648493
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @param string $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sc_muladd($a, $b, $c)
{
$a0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($a, 0, 3)));
$a1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5));
$a2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2));
$a3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7));
$a4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4));
$a5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1));
$a6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6));
$a7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3));
$a8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($a, 21, 3)));
$a9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5));
$a10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2));
$a11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($a, 28, 4)) >> 7));
$b0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($b, 0, 3)));
$b1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5));
$b2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2));
$b3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7));
$b4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4));
$b5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1));
$b6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6));
$b7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3));
$b8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($b, 21, 3)));
$b9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5));
$b10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2));
$b11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($b, 28, 4)) >> 7));
$c0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($c, 0, 3)));
$c1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5));
$c2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2));
$c3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7));
$c4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4));
$c5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1));
$c6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6));
$c7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3));
$c8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($c, 21, 3)));
$c9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5));
$c10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2));
$c11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($c, 28, 4)) >> 7));
/* Can't really avoid the pyramid here: */
/**
* @var ParagonIE_Sodium_Core32_Int64 $s0
* @var ParagonIE_Sodium_Core32_Int64 $s1
* @var ParagonIE_Sodium_Core32_Int64 $s2
* @var ParagonIE_Sodium_Core32_Int64 $s3
* @var ParagonIE_Sodium_Core32_Int64 $s4
* @var ParagonIE_Sodium_Core32_Int64 $s5
* @var ParagonIE_Sodium_Core32_Int64 $s6
* @var ParagonIE_Sodium_Core32_Int64 $s7
* @var ParagonIE_Sodium_Core32_Int64 $s8
* @var ParagonIE_Sodium_Core32_Int64 $s9
* @var ParagonIE_Sodium_Core32_Int64 $s10
* @var ParagonIE_Sodium_Core32_Int64 $s11
* @var ParagonIE_Sodium_Core32_Int64 $s12
* @var ParagonIE_Sodium_Core32_Int64 $s13
* @var ParagonIE_Sodium_Core32_Int64 $s14
* @var ParagonIE_Sodium_Core32_Int64 $s15
* @var ParagonIE_Sodium_Core32_Int64 $s16
* @var ParagonIE_Sodium_Core32_Int64 $s17
* @var ParagonIE_Sodium_Core32_Int64 $s18
* @var ParagonIE_Sodium_Core32_Int64 $s19
* @var ParagonIE_Sodium_Core32_Int64 $s20
* @var ParagonIE_Sodium_Core32_Int64 $s21
* @var ParagonIE_Sodium_Core32_Int64 $s22
* @var ParagonIE_Sodium_Core32_Int64 $s23
*/
$s0 = $c0->addInt64($a0->mulInt64($b0, 24));
$s1 = $c1->addInt64($a0->mulInt64($b1, 24))->addInt64($a1->mulInt64($b0, 24));
$s2 = $c2->addInt64($a0->mulInt64($b2, 24))->addInt64($a1->mulInt64($b1, 24))->addInt64($a2->mulInt64($b0, 24));
$s3 = $c3->addInt64($a0->mulInt64($b3, 24))->addInt64($a1->mulInt64($b2, 24))->addInt64($a2->mulInt64($b1, 24))
->addInt64($a3->mulInt64($b0, 24));
$s4 = $c4->addInt64($a0->mulInt64($b4, 24))->addInt64($a1->mulInt64($b3, 24))->addInt64($a2->mulInt64($b2, 24))
->addInt64($a3->mulInt64($b1, 24))->addInt64($a4->mulInt64($b0, 24));
$s5 = $c5->addInt64($a0->mulInt64($b5, 24))->addInt64($a1->mulInt64($b4, 24))->addInt64($a2->mulInt64($b3, 24))
->addInt64($a3->mulInt64($b2, 24))->addInt64($a4->mulInt64($b1, 24))->addInt64($a5->mulInt64($b0, 24));
$s6 = $c6->addInt64($a0->mulInt64($b6, 24))->addInt64($a1->mulInt64($b5, 24))->addInt64($a2->mulInt64($b4, 24))
->addInt64($a3->mulInt64($b3, 24))->addInt64($a4->mulInt64($b2, 24))->addInt64($a5->mulInt64($b1, 24))
->addInt64($a6->mulInt64($b0, 24));
$s7 = $c7->addInt64($a0->mulInt64($b7, 24))->addInt64($a1->mulInt64($b6, 24))->addInt64($a2->mulInt64($b5, 24))
->addInt64($a3->mulInt64($b4, 24))->addInt64($a4->mulInt64($b3, 24))->addInt64($a5->mulInt64($b2, 24))
->addInt64($a6->mulInt64($b1, 24))->addInt64($a7->mulInt64($b0, 24));
$s8 = $c8->addInt64($a0->mulInt64($b8, 24))->addInt64($a1->mulInt64($b7, 24))->addInt64($a2->mulInt64($b6, 24))
->addInt64($a3->mulInt64($b5, 24))->addInt64($a4->mulInt64($b4, 24))->addInt64($a5->mulInt64($b3, 24))
->addInt64($a6->mulInt64($b2, 24))->addInt64($a7->mulInt64($b1, 24))->addInt64($a8->mulInt64($b0, 24));
$s9 = $c9->addInt64($a0->mulInt64($b9, 24))->addInt64($a1->mulInt64($b8, 24))->addInt64($a2->mulInt64($b7, 24))
->addInt64($a3->mulInt64($b6, 24))->addInt64($a4->mulInt64($b5, 24))->addInt64($a5->mulInt64($b4, 24))
->addInt64($a6->mulInt64($b3, 24))->addInt64($a7->mulInt64($b2, 24))->addInt64($a8->mulInt64($b1, 24))
->addInt64($a9->mulInt64($b0, 24));
$s10 = $c10->addInt64($a0->mulInt64($b10, 24))->addInt64($a1->mulInt64($b9, 24))->addInt64($a2->mulInt64($b8, 24))
->addInt64($a3->mulInt64($b7, 24))->addInt64($a4->mulInt64($b6, 24))->addInt64($a5->mulInt64($b5, 24))
->addInt64($a6->mulInt64($b4, 24))->addInt64($a7->mulInt64($b3, 24))->addInt64($a8->mulInt64($b2, 24))
->addInt64($a9->mulInt64($b1, 24))->addInt64($a10->mulInt64($b0, 24));
$s11 = $c11->addInt64($a0->mulInt64($b11, 24))->addInt64($a1->mulInt64($b10, 24))->addInt64($a2->mulInt64($b9, 24))
->addInt64($a3->mulInt64($b8, 24))->addInt64($a4->mulInt64($b7, 24))->addInt64($a5->mulInt64($b6, 24))
->addInt64($a6->mulInt64($b5, 24))->addInt64($a7->mulInt64($b4, 24))->addInt64($a8->mulInt64($b3, 24))
->addInt64($a9->mulInt64($b2, 24))->addInt64($a10->mulInt64($b1, 24))->addInt64($a11->mulInt64($b0, 24));
$s12 = $a1->mulInt64($b11, 24)->addInt64($a2->mulInt64($b10, 24))->addInt64($a3->mulInt64($b9, 24))
->addInt64($a4->mulInt64($b8, 24))->addInt64($a5->mulInt64($b7, 24))->addInt64($a6->mulInt64($b6, 24))
->addInt64($a7->mulInt64($b5, 24))->addInt64($a8->mulInt64($b4, 24))->addInt64($a9->mulInt64($b3, 24))
->addInt64($a10->mulInt64($b2, 24))->addInt64($a11->mulInt64($b1, 24));
$s13 = $a2->mulInt64($b11, 24)->addInt64($a3->mulInt64($b10, 24))->addInt64($a4->mulInt64($b9, 24))
->addInt64($a5->mulInt64($b8, 24))->addInt64($a6->mulInt64($b7, 24))->addInt64($a7->mulInt64($b6, 24))
->addInt64($a8->mulInt64($b5, 24))->addInt64($a9->mulInt64($b4, 24))->addInt64($a10->mulInt64($b3, 24))
->addInt64($a11->mulInt64($b2, 24));
$s14 = $a3->mulInt64($b11, 24)->addInt64($a4->mulInt64($b10, 24))->addInt64($a5->mulInt64($b9, 24))
->addInt64($a6->mulInt64($b8, 24))->addInt64($a7->mulInt64($b7, 24))->addInt64($a8->mulInt64($b6, 24))
->addInt64($a9->mulInt64($b5, 24))->addInt64($a10->mulInt64($b4, 24))->addInt64($a11->mulInt64($b3, 24));
$s15 = $a4->mulInt64($b11, 24)->addInt64($a5->mulInt64($b10, 24))->addInt64($a6->mulInt64($b9, 24))
->addInt64($a7->mulInt64($b8, 24))->addInt64($a8->mulInt64($b7, 24))->addInt64($a9->mulInt64($b6, 24))
->addInt64($a10->mulInt64($b5, 24))->addInt64($a11->mulInt64($b4, 24));
$s16 = $a5->mulInt64($b11, 24)->addInt64($a6->mulInt64($b10, 24))->addInt64($a7->mulInt64($b9, 24))
->addInt64($a8->mulInt64($b8, 24))->addInt64($a9->mulInt64($b7, 24))->addInt64($a10->mulInt64($b6, 24))
->addInt64($a11->mulInt64($b5, 24));
$s17 = $a6->mulInt64($b11, 24)->addInt64($a7->mulInt64($b10, 24))->addInt64($a8->mulInt64($b9, 24))
->addInt64($a9->mulInt64($b8, 24))->addInt64($a10->mulInt64($b7, 24))->addInt64($a11->mulInt64($b6, 24));
$s18 = $a7->mulInt64($b11, 24)->addInt64($a8->mulInt64($b10, 24))->addInt64($a9->mulInt64($b9, 24))
->addInt64($a10->mulInt64($b8, 24))->addInt64($a11->mulInt64($b7, 24));
$s19 = $a8->mulInt64($b11, 24)->addInt64($a9->mulInt64($b10, 24))->addInt64($a10->mulInt64($b9, 24))
->addInt64($a11->mulInt64($b8, 24));
$s20 = $a9->mulInt64($b11, 24)->addInt64($a10->mulInt64($b10, 24))->addInt64($a11->mulInt64($b9, 24));
$s21 = $a10->mulInt64($b11, 24)->addInt64($a11->mulInt64($b10, 24));
$s22 = $a11->mulInt64($b11, 24);
$s23 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->addInt(1 << 20)->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry2 = $s2->addInt(1 << 20)->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry4 = $s4->addInt(1 << 20)->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry12 = $s12->addInt(1 << 20)->shiftRight(21);
$s13 = $s13->addInt64($carry12);
$s12 = $s12->subInt64($carry12->shiftLeft(21));
$carry14 = $s14->addInt(1 << 20)->shiftRight(21);
$s15 = $s15->addInt64($carry14);
$s14 = $s14->subInt64($carry14->shiftLeft(21));
$carry16 = $s16->addInt(1 << 20)->shiftRight(21);
$s17 = $s17->addInt64($carry16);
$s16 = $s16->subInt64($carry16->shiftLeft(21));
$carry18 = $s18->addInt(1 << 20)->shiftRight(21);
$s19 = $s19->addInt64($carry18);
$s18 = $s18->subInt64($carry18->shiftLeft(21));
$carry20 = $s20->addInt(1 << 20)->shiftRight(21);
$s21 = $s21->addInt64($carry20);
$s20 = $s20->subInt64($carry20->shiftLeft(21));
$carry22 = $s22->addInt(1 << 20)->shiftRight(21);
$s23 = $s23->addInt64($carry22);
$s22 = $s22->subInt64($carry22->shiftLeft(21));
$carry1 = $s1->addInt(1 << 20)->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry3 = $s3->addInt(1 << 20)->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry5 = $s5->addInt(1 << 20)->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$carry13 = $s13->addInt(1 << 20)->shiftRight(21);
$s14 = $s14->addInt64($carry13);
$s13 = $s13->subInt64($carry13->shiftLeft(21));
$carry15 = $s15->addInt(1 << 20)->shiftRight(21);
$s16 = $s16->addInt64($carry15);
$s15 = $s15->subInt64($carry15->shiftLeft(21));
$carry17 = $s17->addInt(1 << 20)->shiftRight(21);
$s18 = $s18->addInt64($carry17);
$s17 = $s17->subInt64($carry17->shiftLeft(21));
$carry19 = $s19->addInt(1 << 20)->shiftRight(21);
$s20 = $s20->addInt64($carry19);
$s19 = $s19->subInt64($carry19->shiftLeft(21));
$carry21 = $s21->addInt(1 << 20)->shiftRight(21);
$s22 = $s22->addInt64($carry21);
$s21 = $s21->subInt64($carry21->shiftLeft(21));
$s11 = $s11->addInt64($s23->mulInt(666643, 20));
$s12 = $s12->addInt64($s23->mulInt(470296, 19));
$s13 = $s13->addInt64($s23->mulInt(654183, 20));
$s14 = $s14->subInt64($s23->mulInt(997805, 20));
$s15 = $s15->addInt64($s23->mulInt(136657, 18));
$s16 = $s16->subInt64($s23->mulInt(683901, 20));
$s10 = $s10->addInt64($s22->mulInt(666643, 20));
$s11 = $s11->addInt64($s22->mulInt(470296, 19));
$s12 = $s12->addInt64($s22->mulInt(654183, 20));
$s13 = $s13->subInt64($s22->mulInt(997805, 20));
$s14 = $s14->addInt64($s22->mulInt(136657, 18));
$s15 = $s15->subInt64($s22->mulInt(683901, 20));
$s9 = $s9->addInt64($s21->mulInt(666643, 20));
$s10 = $s10->addInt64($s21->mulInt(470296, 19));
$s11 = $s11->addInt64($s21->mulInt(654183, 20));
$s12 = $s12->subInt64($s21->mulInt(997805, 20));
$s13 = $s13->addInt64($s21->mulInt(136657, 18));
$s14 = $s14->subInt64($s21->mulInt(683901, 20));
$s8 = $s8->addInt64($s20->mulInt(666643, 20));
$s9 = $s9->addInt64($s20->mulInt(470296, 19));
$s10 = $s10->addInt64($s20->mulInt(654183, 20));
$s11 = $s11->subInt64($s20->mulInt(997805, 20));
$s12 = $s12->addInt64($s20->mulInt(136657, 18));
$s13 = $s13->subInt64($s20->mulInt(683901, 20));
$s7 = $s7->addInt64($s19->mulInt(666643, 20));
$s8 = $s8->addInt64($s19->mulInt(470296, 19));
$s9 = $s9->addInt64($s19->mulInt(654183, 20));
$s10 = $s10->subInt64($s19->mulInt(997805, 20));
$s11 = $s11->addInt64($s19->mulInt(136657, 18));
$s12 = $s12->subInt64($s19->mulInt(683901, 20));
$s6 = $s6->addInt64($s18->mulInt(666643, 20));
$s7 = $s7->addInt64($s18->mulInt(470296, 19));
$s8 = $s8->addInt64($s18->mulInt(654183, 20));
$s9 = $s9->subInt64($s18->mulInt(997805, 20));
$s10 = $s10->addInt64($s18->mulInt(136657, 18));
$s11 = $s11->subInt64($s18->mulInt(683901, 20));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry12 = $s12->addInt(1 << 20)->shiftRight(21);
$s13 = $s13->addInt64($carry12);
$s12 = $s12->subInt64($carry12->shiftLeft(21));
$carry14 = $s14->addInt(1 << 20)->shiftRight(21);
$s15 = $s15->addInt64($carry14);
$s14 = $s14->subInt64($carry14->shiftLeft(21));
$carry16 = $s16->addInt(1 << 20)->shiftRight(21);
$s17 = $s17->addInt64($carry16);
$s16 = $s16->subInt64($carry16->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$carry13 = $s13->addInt(1 << 20)->shiftRight(21);
$s14 = $s14->addInt64($carry13);
$s13 = $s13->subInt64($carry13->shiftLeft(21));
$carry15 = $s15->addInt(1 << 20)->shiftRight(21);
$s16 = $s16->addInt64($carry15);
$s15 = $s15->subInt64($carry15->shiftLeft(21));
$s5 = $s5->addInt64($s17->mulInt(666643, 20));
$s6 = $s6->addInt64($s17->mulInt(470296, 19));
$s7 = $s7->addInt64($s17->mulInt(654183, 20));
$s8 = $s8->subInt64($s17->mulInt(997805, 20));
$s9 = $s9->addInt64($s17->mulInt(136657, 18));
$s10 = $s10->subInt64($s17->mulInt(683901, 20));
$s4 = $s4->addInt64($s16->mulInt(666643, 20));
$s5 = $s5->addInt64($s16->mulInt(470296, 19));
$s6 = $s6->addInt64($s16->mulInt(654183, 20));
$s7 = $s7->subInt64($s16->mulInt(997805, 20));
$s8 = $s8->addInt64($s16->mulInt(136657, 18));
$s9 = $s9->subInt64($s16->mulInt(683901, 20));
$s3 = $s3->addInt64($s15->mulInt(666643, 20));
$s4 = $s4->addInt64($s15->mulInt(470296, 19));
$s5 = $s5->addInt64($s15->mulInt(654183, 20));
$s6 = $s6->subInt64($s15->mulInt(997805, 20));
$s7 = $s7->addInt64($s15->mulInt(136657, 18));
$s8 = $s8->subInt64($s15->mulInt(683901, 20));
$s2 = $s2->addInt64($s14->mulInt(666643, 20));
$s3 = $s3->addInt64($s14->mulInt(470296, 19));
$s4 = $s4->addInt64($s14->mulInt(654183, 20));
$s5 = $s5->subInt64($s14->mulInt(997805, 20));
$s6 = $s6->addInt64($s14->mulInt(136657, 18));
$s7 = $s7->subInt64($s14->mulInt(683901, 20));
$s1 = $s1->addInt64($s13->mulInt(666643, 20));
$s2 = $s2->addInt64($s13->mulInt(470296, 19));
$s3 = $s3->addInt64($s13->mulInt(654183, 20));
$s4 = $s4->subInt64($s13->mulInt(997805, 20));
$s5 = $s5->addInt64($s13->mulInt(136657, 18));
$s6 = $s6->subInt64($s13->mulInt(683901, 20));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->addInt(1 << 20)->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry2 = $s2->addInt(1 << 20)->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry4 = $s4->addInt(1 << 20)->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry1 = $s1->addInt(1 << 20)->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry3 = $s3->addInt(1 << 20)->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry5 = $s5->addInt(1 << 20)->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s8->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry11 = $s11->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s10->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$S0 = $s0->toInt();
$S1 = $s1->toInt();
$S2 = $s2->toInt();
$S3 = $s3->toInt();
$S4 = $s4->toInt();
$S5 = $s5->toInt();
$S6 = $s6->toInt();
$S7 = $s7->toInt();
$S8 = $s8->toInt();
$S9 = $s9->toInt();
$S10 = $s10->toInt();
$S11 = $s11->toInt();
/**
* @var array<int, int>
*/
$arr = array(
(int) (0xff & ($S0 >> 0)),
(int) (0xff & ($S0 >> 8)),
(int) (0xff & (($S0 >> 16) | ($S1 << 5))),
(int) (0xff & ($S1 >> 3)),
(int) (0xff & ($S1 >> 11)),
(int) (0xff & (($S1 >> 19) | ($S2 << 2))),
(int) (0xff & ($S2 >> 6)),
(int) (0xff & (($S2 >> 14) | ($S3 << 7))),
(int) (0xff & ($S3 >> 1)),
(int) (0xff & ($S3 >> 9)),
(int) (0xff & (($S3 >> 17) | ($S4 << 4))),
(int) (0xff & ($S4 >> 4)),
(int) (0xff & ($S4 >> 12)),
(int) (0xff & (($S4 >> 20) | ($S5 << 1))),
(int) (0xff & ($S5 >> 7)),
(int) (0xff & (($S5 >> 15) | ($S6 << 6))),
(int) (0xff & ($S6 >> 2)),
(int) (0xff & ($S6 >> 10)),
(int) (0xff & (($S6 >> 18) | ($S7 << 3))),
(int) (0xff & ($S7 >> 5)),
(int) (0xff & ($S7 >> 13)),
(int) (0xff & ($S8 >> 0)),
(int) (0xff & ($S8 >> 8)),
(int) (0xff & (($S8 >> 16) | ($S9 << 5))),
(int) (0xff & ($S9 >> 3)),
(int) (0xff & ($S9 >> 11)),
(int) (0xff & (($S9 >> 19) | ($S10 << 2))),
(int) (0xff & ($S10 >> 6)),
(int) (0xff & (($S10 >> 14) | ($S11 << 7))),
(int) (0xff & ($S11 >> 1)),
(int) (0xff & ($S11 >> 9)),
(int) (0xff & ($S11 >> 17))
);
return self::intArrayToString($arr);
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sc_reduce($s)
{
/**
* @var ParagonIE_Sodium_Core32_Int64 $s0
* @var ParagonIE_Sodium_Core32_Int64 $s1
* @var ParagonIE_Sodium_Core32_Int64 $s2
* @var ParagonIE_Sodium_Core32_Int64 $s3
* @var ParagonIE_Sodium_Core32_Int64 $s4
* @var ParagonIE_Sodium_Core32_Int64 $s5
* @var ParagonIE_Sodium_Core32_Int64 $s6
* @var ParagonIE_Sodium_Core32_Int64 $s7
* @var ParagonIE_Sodium_Core32_Int64 $s8
* @var ParagonIE_Sodium_Core32_Int64 $s9
* @var ParagonIE_Sodium_Core32_Int64 $s10
* @var ParagonIE_Sodium_Core32_Int64 $s11
* @var ParagonIE_Sodium_Core32_Int64 $s12
* @var ParagonIE_Sodium_Core32_Int64 $s13
* @var ParagonIE_Sodium_Core32_Int64 $s14
* @var ParagonIE_Sodium_Core32_Int64 $s15
* @var ParagonIE_Sodium_Core32_Int64 $s16
* @var ParagonIE_Sodium_Core32_Int64 $s17
* @var ParagonIE_Sodium_Core32_Int64 $s18
* @var ParagonIE_Sodium_Core32_Int64 $s19
* @var ParagonIE_Sodium_Core32_Int64 $s20
* @var ParagonIE_Sodium_Core32_Int64 $s21
* @var ParagonIE_Sodium_Core32_Int64 $s22
* @var ParagonIE_Sodium_Core32_Int64 $s23
*/
$s0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 0, 3)));
$s1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5));
$s2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2));
$s3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7));
$s4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4));
$s5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1));
$s6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6));
$s7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3));
$s8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 21, 3)));
$s9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5));
$s10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2));
$s11 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7));
$s12 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4));
$s13 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1));
$s14 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6));
$s15 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3));
$s16 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 42, 3)));
$s17 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5));
$s18 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2));
$s19 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7));
$s20 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4));
$s21 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1));
$s22 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6));
$s23 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3));
$s11 = $s11->addInt64($s23->mulInt(666643, 20));
$s12 = $s12->addInt64($s23->mulInt(470296, 19));
$s13 = $s13->addInt64($s23->mulInt(654183, 20));
$s14 = $s14->subInt64($s23->mulInt(997805, 20));
$s15 = $s15->addInt64($s23->mulInt(136657, 18));
$s16 = $s16->subInt64($s23->mulInt(683901, 20));
$s10 = $s10->addInt64($s22->mulInt(666643, 20));
$s11 = $s11->addInt64($s22->mulInt(470296, 19));
$s12 = $s12->addInt64($s22->mulInt(654183, 20));
$s13 = $s13->subInt64($s22->mulInt(997805, 20));
$s14 = $s14->addInt64($s22->mulInt(136657, 18));
$s15 = $s15->subInt64($s22->mulInt(683901, 20));
$s9 = $s9->addInt64($s21->mulInt(666643, 20));
$s10 = $s10->addInt64($s21->mulInt(470296, 19));
$s11 = $s11->addInt64($s21->mulInt(654183, 20));
$s12 = $s12->subInt64($s21->mulInt(997805, 20));
$s13 = $s13->addInt64($s21->mulInt(136657, 18));
$s14 = $s14->subInt64($s21->mulInt(683901, 20));
$s8 = $s8->addInt64($s20->mulInt(666643, 20));
$s9 = $s9->addInt64($s20->mulInt(470296, 19));
$s10 = $s10->addInt64($s20->mulInt(654183, 20));
$s11 = $s11->subInt64($s20->mulInt(997805, 20));
$s12 = $s12->addInt64($s20->mulInt(136657, 18));
$s13 = $s13->subInt64($s20->mulInt(683901, 20));
$s7 = $s7->addInt64($s19->mulInt(666643, 20));
$s8 = $s8->addInt64($s19->mulInt(470296, 19));
$s9 = $s9->addInt64($s19->mulInt(654183, 20));
$s10 = $s10->subInt64($s19->mulInt(997805, 20));
$s11 = $s11->addInt64($s19->mulInt(136657, 18));
$s12 = $s12->subInt64($s19->mulInt(683901, 20));
$s6 = $s6->addInt64($s18->mulInt(666643, 20));
$s7 = $s7->addInt64($s18->mulInt(470296, 19));
$s8 = $s8->addInt64($s18->mulInt(654183, 20));
$s9 = $s9->subInt64($s18->mulInt(997805, 20));
$s10 = $s10->addInt64($s18->mulInt(136657, 18));
$s11 = $s11->subInt64($s18->mulInt(683901, 20));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry12 = $s12->addInt(1 << 20)->shiftRight(21);
$s13 = $s13->addInt64($carry12);
$s12 = $s12->subInt64($carry12->shiftLeft(21));
$carry14 = $s14->addInt(1 << 20)->shiftRight(21);
$s15 = $s15->addInt64($carry14);
$s14 = $s14->subInt64($carry14->shiftLeft(21));
$carry16 = $s16->addInt(1 << 20)->shiftRight(21);
$s17 = $s17->addInt64($carry16);
$s16 = $s16->subInt64($carry16->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$carry13 = $s13->addInt(1 << 20)->shiftRight(21);
$s14 = $s14->addInt64($carry13);
$s13 = $s13->subInt64($carry13->shiftLeft(21));
$carry15 = $s15->addInt(1 << 20)->shiftRight(21);
$s16 = $s16->addInt64($carry15);
$s15 = $s15->subInt64($carry15->shiftLeft(21));
$s5 = $s5->addInt64($s17->mulInt(666643, 20));
$s6 = $s6->addInt64($s17->mulInt(470296, 19));
$s7 = $s7->addInt64($s17->mulInt(654183, 20));
$s8 = $s8->subInt64($s17->mulInt(997805, 20));
$s9 = $s9->addInt64($s17->mulInt(136657, 18));
$s10 = $s10->subInt64($s17->mulInt(683901, 20));
$s4 = $s4->addInt64($s16->mulInt(666643, 20));
$s5 = $s5->addInt64($s16->mulInt(470296, 19));
$s6 = $s6->addInt64($s16->mulInt(654183, 20));
$s7 = $s7->subInt64($s16->mulInt(997805, 20));
$s8 = $s8->addInt64($s16->mulInt(136657, 18));
$s9 = $s9->subInt64($s16->mulInt(683901, 20));
$s3 = $s3->addInt64($s15->mulInt(666643, 20));
$s4 = $s4->addInt64($s15->mulInt(470296, 19));
$s5 = $s5->addInt64($s15->mulInt(654183, 20));
$s6 = $s6->subInt64($s15->mulInt(997805, 20));
$s7 = $s7->addInt64($s15->mulInt(136657, 18));
$s8 = $s8->subInt64($s15->mulInt(683901, 20));
$s2 = $s2->addInt64($s14->mulInt(666643, 20));
$s3 = $s3->addInt64($s14->mulInt(470296, 19));
$s4 = $s4->addInt64($s14->mulInt(654183, 20));
$s5 = $s5->subInt64($s14->mulInt(997805, 20));
$s6 = $s6->addInt64($s14->mulInt(136657, 18));
$s7 = $s7->subInt64($s14->mulInt(683901, 20));
$s1 = $s1->addInt64($s13->mulInt(666643, 20));
$s2 = $s2->addInt64($s13->mulInt(470296, 19));
$s3 = $s3->addInt64($s13->mulInt(654183, 20));
$s4 = $s4->subInt64($s13->mulInt(997805, 20));
$s5 = $s5->addInt64($s13->mulInt(136657, 18));
$s6 = $s6->subInt64($s13->mulInt(683901, 20));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->addInt(1 << 20)->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry2 = $s2->addInt(1 << 20)->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry4 = $s4->addInt(1 << 20)->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry1 = $s1->addInt(1 << 20)->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry3 = $s3->addInt(1 << 20)->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry5 = $s5->addInt(1 << 20)->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s8->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry11 = $s11->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s8->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$S0 = $s0->toInt32()->toInt();
$S1 = $s1->toInt32()->toInt();
$S2 = $s2->toInt32()->toInt();
$S3 = $s3->toInt32()->toInt();
$S4 = $s4->toInt32()->toInt();
$S5 = $s5->toInt32()->toInt();
$S6 = $s6->toInt32()->toInt();
$S7 = $s7->toInt32()->toInt();
$S8 = $s8->toInt32()->toInt();
$S9 = $s9->toInt32()->toInt();
$S10 = $s10->toInt32()->toInt();
$S11 = $s11->toInt32()->toInt();
/**
* @var array<int, int>
*/
$arr = array(
(int) ($S0 >> 0),
(int) ($S0 >> 8),
(int) (($S0 >> 16) | ($S1 << 5)),
(int) ($S1 >> 3),
(int) ($S1 >> 11),
(int) (($S1 >> 19) | ($S2 << 2)),
(int) ($S2 >> 6),
(int) (($S2 >> 14) | ($S3 << 7)),
(int) ($S3 >> 1),
(int) ($S3 >> 9),
(int) (($S3 >> 17) | ($S4 << 4)),
(int) ($S4 >> 4),
(int) ($S4 >> 12),
(int) (($S4 >> 20) | ($S5 << 1)),
(int) ($S5 >> 7),
(int) (($S5 >> 15) | ($S6 << 6)),
(int) ($S6 >> 2),
(int) ($S6 >> 10),
(int) (($S6 >> 18) | ($S7 << 3)),
(int) ($S7 >> 5),
(int) ($S7 >> 13),
(int) ($S8 >> 0),
(int) ($S8 >> 8),
(int) (($S8 >> 16) | ($S9 << 5)),
(int) ($S9 >> 3),
(int) ($S9 >> 11),
(int) (($S9 >> 19) | ($S10 << 2)),
(int) ($S10 >> 6),
(int) (($S10 >> 14) | ($S11 << 7)),
(int) ($S11 >> 1),
(int) ($S11 >> 9),
(int) $S11 >> 17
);
return self::intArrayToString($arr);
}
/**
* multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_mul_l(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A)
{
$aslide = array(
13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
);
/** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai size 8 */
$Ai = array();
# ge_p3_to_cached(&Ai[0], A);
$Ai[0] = self::ge_p3_to_cached($A);
# ge_p3_dbl(&t, A);
$t = self::ge_p3_dbl($A);
# ge_p1p1_to_p3(&A2, &t);
$A2 = self::ge_p1p1_to_p3($t);
for ($i = 1; $i < 8; ++$i) {
# ge_add(&t, &A2, &Ai[0]);
$t = self::ge_add($A2, $Ai[$i - 1]);
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_p3_to_cached(&Ai[i], &u);
$Ai[$i] = self::ge_p3_to_cached($u);
}
$r = self::ge_p3_0();
for ($i = 252; $i >= 0; --$i) {
$t = self::ge_p3_dbl($r);
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_add(&t, &u, &Ai[aslide[i] / 2]);
$t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
$t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
}
}
# ge_p1p1_to_p3(r, &t);
return self::ge_p1p1_to_p3($t);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_XChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_XChaCha20
*/
class ParagonIE_Sodium_Core32_XChaCha20 extends ParagonIE_Sodium_Core32_HChaCha20
{
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
self::substr($nonce, 16, 8),
$ic
),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8),
$ic
),
$message
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_HSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_HSalsa20
*/
abstract class ParagonIE_Sodium_Core32_HSalsa20 extends ParagonIE_Sodium_Core32_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function hsalsa20($in, $k, $c = null)
{
/**
* @var ParagonIE_Sodium_Core32_Int32 $x0
* @var ParagonIE_Sodium_Core32_Int32 $x1
* @var ParagonIE_Sodium_Core32_Int32 $x2
* @var ParagonIE_Sodium_Core32_Int32 $x3
* @var ParagonIE_Sodium_Core32_Int32 $x4
* @var ParagonIE_Sodium_Core32_Int32 $x5
* @var ParagonIE_Sodium_Core32_Int32 $x6
* @var ParagonIE_Sodium_Core32_Int32 $x7
* @var ParagonIE_Sodium_Core32_Int32 $x8
* @var ParagonIE_Sodium_Core32_Int32 $x9
* @var ParagonIE_Sodium_Core32_Int32 $x10
* @var ParagonIE_Sodium_Core32_Int32 $x11
* @var ParagonIE_Sodium_Core32_Int32 $x12
* @var ParagonIE_Sodium_Core32_Int32 $x13
* @var ParagonIE_Sodium_Core32_Int32 $x14
* @var ParagonIE_Sodium_Core32_Int32 $x15
* @var ParagonIE_Sodium_Core32_Int32 $j0
* @var ParagonIE_Sodium_Core32_Int32 $j1
* @var ParagonIE_Sodium_Core32_Int32 $j2
* @var ParagonIE_Sodium_Core32_Int32 $j3
* @var ParagonIE_Sodium_Core32_Int32 $j4
* @var ParagonIE_Sodium_Core32_Int32 $j5
* @var ParagonIE_Sodium_Core32_Int32 $j6
* @var ParagonIE_Sodium_Core32_Int32 $j7
* @var ParagonIE_Sodium_Core32_Int32 $j8
* @var ParagonIE_Sodium_Core32_Int32 $j9
* @var ParagonIE_Sodium_Core32_Int32 $j10
* @var ParagonIE_Sodium_Core32_Int32 $j11
* @var ParagonIE_Sodium_Core32_Int32 $j12
* @var ParagonIE_Sodium_Core32_Int32 $j13
* @var ParagonIE_Sodium_Core32_Int32 $j14
* @var ParagonIE_Sodium_Core32_Int32 $j15
*/
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$x0 = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$x5 = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$x10 = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$x15 = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
} else {
$x0 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$x5 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$x10 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$x15 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$x1 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4));
$x2 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4));
$x3 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4));
$x4 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4));
$x6 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$x7 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$x8 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$x9 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
$x11 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4));
$x12 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4));
$x13 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4));
$x14 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 = $x4->xorInt32($x0->addInt32($x12)->rotateLeft(7));
$x8 = $x8->xorInt32($x4->addInt32($x0)->rotateLeft(9));
$x12 = $x12->xorInt32($x8->addInt32($x4)->rotateLeft(13));
$x0 = $x0->xorInt32($x12->addInt32($x8)->rotateLeft(18));
$x9 = $x9->xorInt32($x5->addInt32($x1)->rotateLeft(7));
$x13 = $x13->xorInt32($x9->addInt32($x5)->rotateLeft(9));
$x1 = $x1->xorInt32($x13->addInt32($x9)->rotateLeft(13));
$x5 = $x5->xorInt32($x1->addInt32($x13)->rotateLeft(18));
$x14 = $x14->xorInt32($x10->addInt32($x6)->rotateLeft(7));
$x2 = $x2->xorInt32($x14->addInt32($x10)->rotateLeft(9));
$x6 = $x6->xorInt32($x2->addInt32($x14)->rotateLeft(13));
$x10 = $x10->xorInt32($x6->addInt32($x2)->rotateLeft(18));
$x3 = $x3->xorInt32($x15->addInt32($x11)->rotateLeft(7));
$x7 = $x7->xorInt32($x3->addInt32($x15)->rotateLeft(9));
$x11 = $x11->xorInt32($x7->addInt32($x3)->rotateLeft(13));
$x15 = $x15->xorInt32($x11->addInt32($x7)->rotateLeft(18));
$x1 = $x1->xorInt32($x0->addInt32($x3)->rotateLeft(7));
$x2 = $x2->xorInt32($x1->addInt32($x0)->rotateLeft(9));
$x3 = $x3->xorInt32($x2->addInt32($x1)->rotateLeft(13));
$x0 = $x0->xorInt32($x3->addInt32($x2)->rotateLeft(18));
$x6 = $x6->xorInt32($x5->addInt32($x4)->rotateLeft(7));
$x7 = $x7->xorInt32($x6->addInt32($x5)->rotateLeft(9));
$x4 = $x4->xorInt32($x7->addInt32($x6)->rotateLeft(13));
$x5 = $x5->xorInt32($x4->addInt32($x7)->rotateLeft(18));
$x11 = $x11->xorInt32($x10->addInt32($x9)->rotateLeft(7));
$x8 = $x8->xorInt32($x11->addInt32($x10)->rotateLeft(9));
$x9 = $x9->xorInt32($x8->addInt32($x11)->rotateLeft(13));
$x10 = $x10->xorInt32($x9->addInt32($x8)->rotateLeft(18));
$x12 = $x12->xorInt32($x15->addInt32($x14)->rotateLeft(7));
$x13 = $x13->xorInt32($x12->addInt32($x15)->rotateLeft(9));
$x14 = $x14->xorInt32($x13->addInt32($x12)->rotateLeft(13));
$x15 = $x15->xorInt32($x14->addInt32($x13)->rotateLeft(18));
}
return $x0->toReverseString() .
$x5->toReverseString() .
$x10->toReverseString() .
$x15->toReverseString() .
$x6->toReverseString() .
$x7->toReverseString() .
$x8->toReverseString() .
$x9->toReverseString();
}
}
<?php
/**
* Class ParagonIE_Sodium_Core32_Int64
*
* Encapsulates a 64-bit integer.
*
* These are immutable. It always returns a new instance.
*/
class ParagonIE_Sodium_Core32_Int64
{
/**
* @var array<int, int> - four 16-bit integers
*/
public $limbs = array(0, 0, 0, 0);
/**
* @var int
*/
public $overflow = 0;
/**
* @var bool
*/
public $unsignedInt = false;
/**
* ParagonIE_Sodium_Core32_Int64 constructor.
* @param array $array
* @param bool $unsignedInt
*/
public function __construct($array = array(0, 0, 0, 0), $unsignedInt = false)
{
$this->limbs = array(
(int) $array[0],
(int) $array[1],
(int) $array[2],
(int) $array[3]
);
$this->overflow = 0;
$this->unsignedInt = $unsignedInt;
}
/**
* Adds two int64 objects
*
* @param ParagonIE_Sodium_Core32_Int64 $addend
* @return ParagonIE_Sodium_Core32_Int64
*/
public function addInt64(ParagonIE_Sodium_Core32_Int64 $addend)
{
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$i2 = $this->limbs[2];
$i3 = $this->limbs[3];
$j0 = $addend->limbs[0];
$j1 = $addend->limbs[1];
$j2 = $addend->limbs[2];
$j3 = $addend->limbs[3];
$r3 = $i3 + ($j3 & 0xffff);
$carry = $r3 >> 16;
$r2 = $i2 + ($j2 & 0xffff) + $carry;
$carry = $r2 >> 16;
$r1 = $i1 + ($j1 & 0xffff) + $carry;
$carry = $r1 >> 16;
$r0 = $i0 + ($j0 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$r2 &= 0xffff;
$r3 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int64(
array($r0, $r1, $r2, $r3)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* Adds a normal integer to an int64 object
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function addInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
/** @var int $int */
$int = (int) $int;
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$i2 = $this->limbs[2];
$i3 = $this->limbs[3];
$r3 = $i3 + ($int & 0xffff);
$carry = $r3 >> 16;
$r2 = $i2 + (($int >> 16) & 0xffff) + $carry;
$carry = $r2 >> 16;
$r1 = $i1 + $carry;
$carry = $r1 >> 16;
$r0 = $i0 + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$r2 &= 0xffff;
$r3 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int64(
array($r0, $r1, $r2, $r3)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param int $b
* @return int
*/
public function compareInt($b = 0)
{
$gt = 0;
$eq = 1;
$i = 4;
$j = 0;
while ($i > 0) {
--$i;
/** @var int $x1 */
$x1 = $this->limbs[$i];
/** @var int $x2 */
$x2 = ($b >> ($j << 4)) & 0xffff;
/** int */
$gt |= (($x2 - $x1) >> 8) & $eq;
/** int */
$eq &= (($x2 ^ $x1) - 1) >> 8;
}
return ($gt + $gt - $eq) + 1;
}
/**
* @param int $b
* @return bool
*/
public function isGreaterThan($b = 0)
{
return $this->compareInt($b) > 0;
}
/**
* @param int $b
* @return bool
*/
public function isLessThanInt($b = 0)
{
return $this->compareInt($b) < 0;
}
/**
* @param int $hi
* @param int $lo
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mask64($hi = 0, $lo = 0)
{
/** @var int $a */
$a = ($hi >> 16) & 0xffff;
/** @var int $b */
$b = ($hi) & 0xffff;
/** @var int $c */
$c = ($lo >> 16) & 0xffff;
/** @var int $d */
$d = ($lo & 0xffff);
return new ParagonIE_Sodium_Core32_Int64(
array(
$this->limbs[0] & $a,
$this->limbs[1] & $b,
$this->limbs[2] & $c,
$this->limbs[3] & $d
),
$this->unsignedInt
);
}
/**
* @param int $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
*/
public function mulInt($int = 0, $size = 0)
{
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulIntFast($int);
}
ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
/** @var int $int */
$int = (int) $int;
/** @var int $size */
$size = (int) $size;
if (!$size) {
$size = 63;
}
$a = clone $this;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$ret2 = 0;
$ret3 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$a2 = $a->limbs[2];
$a3 = $a->limbs[3];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$mask = -($int & 1);
$x0 = $a0 & $mask;
$x1 = $a1 & $mask;
$x2 = $a2 & $mask;
$x3 = $a3 & $mask;
$ret3 += $x3;
$c = $ret3 >> 16;
$ret2 += $x2 + $c;
$c = $ret2 >> 16;
$ret1 += $x1 + $c;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$ret2 &= 0xffff;
$ret3 &= 0xffff;
$a3 = $a3 << 1;
$x3 = $a3 >> 16;
$a2 = ($a2 << 1) | $x3;
$x2 = $a2 >> 16;
$a1 = ($a1 << 1) | $x2;
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$a2 &= 0xffff;
$a3 &= 0xffff;
$int >>= 1;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
$return->limbs[2] = $ret2;
$return->limbs[3] = $ret3;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $A
* @param ParagonIE_Sodium_Core32_Int64 $B
* @return array<int, ParagonIE_Sodium_Core32_Int64>
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedInferredReturnType
*/
public static function ctSelect(
ParagonIE_Sodium_Core32_Int64 $A,
ParagonIE_Sodium_Core32_Int64 $B
) {
$a = clone $A;
$b = clone $B;
/** @var int $aNeg */
$aNeg = ($a->limbs[0] >> 15) & 1;
/** @var int $bNeg */
$bNeg = ($b->limbs[0] >> 15) & 1;
/** @var int $m */
$m = (-($aNeg & $bNeg)) | 1;
/** @var int $swap */
$swap = $bNeg & ~$aNeg;
/** @var int $d */
$d = -$swap;
/*
if ($bNeg && !$aNeg) {
$a = clone $int;
$b = clone $this;
} elseif($bNeg && $aNeg) {
$a = $this->mulInt(-1);
$b = $int->mulInt(-1);
}
*/
$x = $a->xorInt64($b)->mask64($d, $d);
return array(
$a->xorInt64($x)->mulInt($m),
$b->xorInt64($x)->mulInt($m)
);
}
/**
* @param array<int, int> $a
* @param array<int, int> $b
* @param int $baseLog2
* @return array<int, int>
*/
public function multiplyLong(array $a, array $b, $baseLog2 = 16)
{
$a_l = count($a);
$b_l = count($b);
/** @var array<int, int> $r */
$r = array_fill(0, $a_l + $b_l + 1, 0);
$base = 1 << $baseLog2;
for ($i = 0; $i < $a_l; ++$i) {
$a_i = $a[$i];
for ($j = 0; $j < $a_l; ++$j) {
$b_j = $b[$j];
$product = (($a_i * $b_j) + $r[$i + $j]);
$carry = (((int) $product >> $baseLog2) & 0xffff);
$r[$i + $j] = ((int) $product - (int) ($carry * $base)) & 0xffff;
$r[$i + $j + 1] += $carry;
}
}
return array_slice($r, 0, 5);
}
/**
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mulIntFast($int)
{
// Handle negative numbers
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($int >> 31) & 1;
$a = array_reverse($this->limbs);
$b = array(
$int & 0xffff,
($int >> 16) & 0xffff,
-$bNeg & 0xffff,
-$bNeg & 0xffff
);
if ($aNeg) {
for ($i = 0; $i < 4; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 4; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
// Multiply
$res = $this->multiplyLong($a, $b);
// Re-apply negation to results
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 4; ++$i) {
$res[$i] = (0xffff ^ $res[$i]) & 0xffff;
}
// Handle integer overflow
$c = 1;
for ($i = 0; $i < 4; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
// Return our values
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs = array(
$res[3] & 0xffff,
$res[2] & 0xffff,
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 4) {
$return->overflow = $res[4] & 0xffff;
}
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $right
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mulInt64Fast(ParagonIE_Sodium_Core32_Int64 $right)
{
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($right->limbs[0] >> 15) & 1;
$a = array_reverse($this->limbs);
$b = array_reverse($right->limbs);
if ($aNeg) {
for ($i = 0; $i < 4; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 4; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
$res = $this->multiplyLong($a, $b);
if ($aNeg !== $bNeg) {
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 4; ++$i) {
$res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
}
$c = 1;
for ($i = 0; $i < 4; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
}
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs = array(
$res[3] & 0xffff,
$res[2] & 0xffff,
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 4) {
$return->overflow = $res[4];
}
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
*/
public function mulInt64(ParagonIE_Sodium_Core32_Int64 $int, $size = 0)
{
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulInt64Fast($int);
}
ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
if (!$size) {
$size = 63;
}
list($a, $b) = self::ctSelect($this, $int);
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$ret2 = 0;
$ret3 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$a2 = $a->limbs[2];
$a3 = $a->limbs[3];
$b0 = $b->limbs[0];
$b1 = $b->limbs[1];
$b2 = $b->limbs[2];
$b3 = $b->limbs[3];
/** @var int $size */
/** @var int $i */
for ($i = (int) $size; $i >= 0; --$i) {
$mask = -($b3 & 1);
$x0 = $a0 & $mask;
$x1 = $a1 & $mask;
$x2 = $a2 & $mask;
$x3 = $a3 & $mask;
$ret3 += $x3;
$c = $ret3 >> 16;
$ret2 += $x2 + $c;
$c = $ret2 >> 16;
$ret1 += $x1 + $c;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$ret2 &= 0xffff;
$ret3 &= 0xffff;
$a3 = $a3 << 1;
$x3 = $a3 >> 16;
$a2 = ($a2 << 1) | $x3;
$x2 = $a2 >> 16;
$a1 = ($a1 << 1) | $x2;
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$a2 &= 0xffff;
$a3 &= 0xffff;
$x0 = ($b0 & 1) << 16;
$x1 = ($b1 & 1) << 16;
$x2 = ($b2 & 1) << 16;
$b0 = ($b0 >> 1);
$b1 = (($b1 | $x0) >> 1);
$b2 = (($b2 | $x1) >> 1);
$b3 = (($b3 | $x2) >> 1);
$b0 &= 0xffff;
$b1 &= 0xffff;
$b2 &= 0xffff;
$b3 &= 0xffff;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
$return->limbs[2] = $ret2;
$return->limbs[3] = $ret3;
return $return;
}
/**
* OR this 64-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function orInt64(ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] | $b->limbs[0]),
(int) ($this->limbs[1] | $b->limbs[1]),
(int) ($this->limbs[2] | $b->limbs[2]),
(int) ($this->limbs[3] | $b->limbs[3])
);
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 3;
/** @var int $sub_shift */
$sub_shift = $c & 15;
for ($i = 3; $i >= 0; --$i) {
/** @var int $j */
$j = ($i + $idx_shift) & 3;
/** @var int $k */
$k = ($i + $idx_shift + 1) & 3;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) << $sub_shift)
|
((int) ($myLimbs[$k]) >> (16 - $sub_shift))
) & 0xffff
);
}
}
return $return;
}
/**
* Rotate to the right
*
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
/** @var ParagonIE_Sodium_Core32_Int64 $return */
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 3;
/** @var int $sub_shift */
$sub_shift = $c & 15;
for ($i = 3; $i >= 0; --$i) {
/** @var int $j */
$j = ($i - $idx_shift) & 3;
/** @var int $k */
$k = ($i - $idx_shift - 1) & 3;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) >> (int) ($sub_shift))
|
((int) ($myLimbs[$k]) << (16 - (int) ($sub_shift)))
) & 0xffff
);
}
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function shiftLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
if ($c >= 16) {
if ($c >= 48) {
$return->limbs = array(
$this->limbs[3], 0, 0, 0
);
} elseif ($c >= 32) {
$return->limbs = array(
$this->limbs[2], $this->limbs[3], 0, 0
);
} else {
$return->limbs = array(
$this->limbs[1], $this->limbs[2], $this->limbs[3], 0
);
}
return $return->shiftLeft($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftRight(-$c);
} else {
if (!is_int($c)) {
throw new TypeError();
}
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = ($this->limbs[$i] << $c) | ($carry & 0xffff);
$return->limbs[$i] = (int) ($tmp & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
}
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function shiftRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
$c = (int) $c;
/** @var int $c */
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
$negative = -(($this->limbs[0] >> 15) & 1);
if ($c >= 16) {
if ($c >= 48) {
$return->limbs = array(
(int) ($negative & 0xffff),
(int) ($negative & 0xffff),
(int) ($negative & 0xffff),
(int) $this->limbs[0]
);
} elseif ($c >= 32) {
$return->limbs = array(
(int) ($negative & 0xffff),
(int) ($negative & 0xffff),
(int) $this->limbs[0],
(int) $this->limbs[1]
);
} else {
$return->limbs = array(
(int) ($negative & 0xffff),
(int) $this->limbs[0],
(int) $this->limbs[1],
(int) $this->limbs[2]
);
}
return $return->shiftRight($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
return $this->shiftLeft(-$c);
} else {
if (!is_int($c)) {
throw new TypeError();
}
/** @var int $carryRight */
$carryRight = ($negative & 0xffff);
$mask = (int) (((1 << ($c + 1)) - 1) & 0xffff);
for ($i = 0; $i < 4; ++$i) {
$return->limbs[$i] = (int) (
(($this->limbs[$i] >> $c) | ($carryRight << (16 - $c))) & 0xffff
);
$carryRight = (int) ($this->limbs[$i] & $mask);
}
}
return $return;
}
/**
* Subtract a normal integer from an int64 object.
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function subInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
$int = (int) $int;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] - (($int >> 16) & 0xffff) + $carry;
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[$i] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* The difference between two Int64 objects.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function subInt64(ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] - $b->limbs[$i] + $carry;
/** @var int $carry */
$carry = ($tmp >> 16);
$return->limbs[$i] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* XOR this 64-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function xorInt64(ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] ^ $b->limbs[0]),
(int) ($this->limbs[1] ^ $b->limbs[1]),
(int) ($this->limbs[2] ^ $b->limbs[2]),
(int) ($this->limbs[3] ^ $b->limbs[3])
);
return $return;
}
/**
* @param int $low
* @param int $high
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInts($low, $high)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($low, 'int', 1);
ParagonIE_Sodium_Core32_Util::declareScalarType($high, 'int', 2);
$high = (int) $high;
$low = (int) $low;
return new ParagonIE_Sodium_Core32_Int64(
array(
(int) (($high >> 16) & 0xffff),
(int) ($high & 0xffff),
(int) (($low >> 16) & 0xffff),
(int) ($low & 0xffff)
)
);
}
/**
* @param int $low
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInt($low)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($low, 'int', 1);
$low = (int) $low;
return new ParagonIE_Sodium_Core32_Int64(
array(
0,
0,
(int) (($low >> 16) & 0xffff),
(int) ($low & 0xffff)
)
);
}
/**
* @return int
*/
public function toInt()
{
return (int) (
(($this->limbs[2] & 0xffff) << 16)
|
($this->limbs[3] & 0xffff)
);
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) {
throw new RangeException(
'String must be 8 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8);
$return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff);
$return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8);
$return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff);
$return->limbs[2] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff) << 8);
$return->limbs[2] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff);
$return->limbs[3] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff) << 8);
$return->limbs[3] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff);
return $return;
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromReverseString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) {
throw new RangeException(
'String must be 8 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff) << 8);
$return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff);
$return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff) << 8);
$return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff);
$return->limbs[2] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8);
$return->limbs[2] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff);
$return->limbs[3] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8);
$return->limbs[3] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff);
return $return;
}
/**
* @return array<int, int>
*/
public function toArray()
{
return array(
(int) ((($this->limbs[0] & 0xffff) << 16) | ($this->limbs[1] & 0xffff)),
(int) ((($this->limbs[2] & 0xffff) << 16) | ($this->limbs[3] & 0xffff))
);
}
/**
* @return ParagonIE_Sodium_Core32_Int32
*/
public function toInt32()
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ($this->limbs[2]);
$return->limbs[1] = (int) ($this->limbs[3]);
$return->unsignedInt = $this->unsignedInt;
$return->overflow = (int) (ParagonIE_Sodium_Core32_Util::abs($this->limbs[1], 16) & 0xffff);
return $return;
}
/**
* @return ParagonIE_Sodium_Core32_Int64
*/
public function toInt64()
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) ($this->limbs[0]);
$return->limbs[1] = (int) ($this->limbs[1]);
$return->limbs[2] = (int) ($this->limbs[2]);
$return->limbs[3] = (int) ($this->limbs[3]);
$return->unsignedInt = $this->unsignedInt;
$return->overflow = ParagonIE_Sodium_Core32_Util::abs($this->overflow);
return $return;
}
/**
* @param bool $bool
* @return self
*/
public function setUnsignedInt($bool = false)
{
$this->unsignedInt = !empty($bool);
return $this;
}
/**
* @return string
* @throws TypeError
*/
public function toString()
{
return ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[2] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[3] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] & 0xff);
}
/**
* @return string
* @throws TypeError
*/
public function toReverseString()
{
return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[3] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[2] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->toString();
} catch (TypeError $ex) {
// PHP engine can't handle exceptions from __toString()
return '';
}
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_ChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20
*/
class ParagonIE_Sodium_Core32_ChaCha20 extends ParagonIE_Sodium_Core32_Util
{
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int32 $a
* @param ParagonIE_Sodium_Core32_Int32 $b
* @param ParagonIE_Sodium_Core32_Int32 $c
* @param ParagonIE_Sodium_Core32_Int32 $d
* @return array<int, ParagonIE_Sodium_Core32_Int32>
* @throws SodiumException
* @throws TypeError
*/
protected static function quarterRound(
ParagonIE_Sodium_Core32_Int32 $a,
ParagonIE_Sodium_Core32_Int32 $b,
ParagonIE_Sodium_Core32_Int32 $c,
ParagonIE_Sodium_Core32_Int32 $d
) {
/** @var ParagonIE_Sodium_Core32_Int32 $a */
/** @var ParagonIE_Sodium_Core32_Int32 $b */
/** @var ParagonIE_Sodium_Core32_Int32 $c */
/** @var ParagonIE_Sodium_Core32_Int32 $d */
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
$a = $a->addInt32($b);
$d = $d->xorInt32($a)->rotateLeft(16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
$c = $c->addInt32($d);
$b = $b->xorInt32($c)->rotateLeft(12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
$a = $a->addInt32($b);
$d = $d->xorInt32($a)->rotateLeft(8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
$c = $c->addInt32($d);
$b = $b->xorInt32($c)->rotateLeft(7);
return array($a, $b, $c, $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function encryptBytes(
ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx,
$message = ''
) {
$bytes = self::strlen($message);
/** @var ParagonIE_Sodium_Core32_Int32 $x0 */
/** @var ParagonIE_Sodium_Core32_Int32 $x1 */
/** @var ParagonIE_Sodium_Core32_Int32 $x2 */
/** @var ParagonIE_Sodium_Core32_Int32 $x3 */
/** @var ParagonIE_Sodium_Core32_Int32 $x4 */
/** @var ParagonIE_Sodium_Core32_Int32 $x5 */
/** @var ParagonIE_Sodium_Core32_Int32 $x6 */
/** @var ParagonIE_Sodium_Core32_Int32 $x7 */
/** @var ParagonIE_Sodium_Core32_Int32 $x8 */
/** @var ParagonIE_Sodium_Core32_Int32 $x9 */
/** @var ParagonIE_Sodium_Core32_Int32 $x10 */
/** @var ParagonIE_Sodium_Core32_Int32 $x11 */
/** @var ParagonIE_Sodium_Core32_Int32 $x12 */
/** @var ParagonIE_Sodium_Core32_Int32 $x13 */
/** @var ParagonIE_Sodium_Core32_Int32 $x14 */
/** @var ParagonIE_Sodium_Core32_Int32 $x15 */
/*
j0 = ctx->input[0];
j1 = ctx->input[1];
j2 = ctx->input[2];
j3 = ctx->input[3];
j4 = ctx->input[4];
j5 = ctx->input[5];
j6 = ctx->input[6];
j7 = ctx->input[7];
j8 = ctx->input[8];
j9 = ctx->input[9];
j10 = ctx->input[10];
j11 = ctx->input[11];
j12 = ctx->input[12];
j13 = ctx->input[13];
j14 = ctx->input[14];
j15 = ctx->input[15];
*/
/** @var ParagonIE_Sodium_Core32_Int32 $j0 */
$j0 = $ctx[0];
/** @var ParagonIE_Sodium_Core32_Int32 $j1 */
$j1 = $ctx[1];
/** @var ParagonIE_Sodium_Core32_Int32 $j2 */
$j2 = $ctx[2];
/** @var ParagonIE_Sodium_Core32_Int32 $j3 */
$j3 = $ctx[3];
/** @var ParagonIE_Sodium_Core32_Int32 $j4 */
$j4 = $ctx[4];
/** @var ParagonIE_Sodium_Core32_Int32 $j5 */
$j5 = $ctx[5];
/** @var ParagonIE_Sodium_Core32_Int32 $j6 */
$j6 = $ctx[6];
/** @var ParagonIE_Sodium_Core32_Int32 $j7 */
$j7 = $ctx[7];
/** @var ParagonIE_Sodium_Core32_Int32 $j8 */
$j8 = $ctx[8];
/** @var ParagonIE_Sodium_Core32_Int32 $j9 */
$j9 = $ctx[9];
/** @var ParagonIE_Sodium_Core32_Int32 $j10 */
$j10 = $ctx[10];
/** @var ParagonIE_Sodium_Core32_Int32 $j11 */
$j11 = $ctx[11];
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
$j12 = $ctx[12];
/** @var ParagonIE_Sodium_Core32_Int32 $j13 */
$j13 = $ctx[13];
/** @var ParagonIE_Sodium_Core32_Int32 $j14 */
$j14 = $ctx[14];
/** @var ParagonIE_Sodium_Core32_Int32 $j15 */
$j15 = $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= str_repeat("\x00", 64 - $bytes);
}
$x0 = clone $j0;
$x1 = clone $j1;
$x2 = clone $j2;
$x3 = clone $j3;
$x4 = clone $j4;
$x5 = clone $j5;
$x6 = clone $j6;
$x7 = clone $j7;
$x8 = clone $j8;
$x9 = clone $j9;
$x10 = clone $j10;
$x11 = clone $j11;
$x12 = clone $j12;
$x13 = clone $j13;
$x14 = clone $j14;
$x15 = clone $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
/*
x0 = PLUS(x0, j0);
x1 = PLUS(x1, j1);
x2 = PLUS(x2, j2);
x3 = PLUS(x3, j3);
x4 = PLUS(x4, j4);
x5 = PLUS(x5, j5);
x6 = PLUS(x6, j6);
x7 = PLUS(x7, j7);
x8 = PLUS(x8, j8);
x9 = PLUS(x9, j9);
x10 = PLUS(x10, j10);
x11 = PLUS(x11, j11);
x12 = PLUS(x12, j12);
x13 = PLUS(x13, j13);
x14 = PLUS(x14, j14);
x15 = PLUS(x15, j15);
*/
$x0 = $x0->addInt32($j0);
$x1 = $x1->addInt32($j1);
$x2 = $x2->addInt32($j2);
$x3 = $x3->addInt32($j3);
$x4 = $x4->addInt32($j4);
$x5 = $x5->addInt32($j5);
$x6 = $x6->addInt32($j6);
$x7 = $x7->addInt32($j7);
$x8 = $x8->addInt32($j8);
$x9 = $x9->addInt32($j9);
$x10 = $x10->addInt32($j10);
$x11 = $x11->addInt32($j11);
$x12 = $x12->addInt32($j12);
$x13 = $x13->addInt32($j13);
$x14 = $x14->addInt32($j14);
$x15 = $x15->addInt32($j15);
/*
x0 = XOR(x0, LOAD32_LE(m + 0));
x1 = XOR(x1, LOAD32_LE(m + 4));
x2 = XOR(x2, LOAD32_LE(m + 8));
x3 = XOR(x3, LOAD32_LE(m + 12));
x4 = XOR(x4, LOAD32_LE(m + 16));
x5 = XOR(x5, LOAD32_LE(m + 20));
x6 = XOR(x6, LOAD32_LE(m + 24));
x7 = XOR(x7, LOAD32_LE(m + 28));
x8 = XOR(x8, LOAD32_LE(m + 32));
x9 = XOR(x9, LOAD32_LE(m + 36));
x10 = XOR(x10, LOAD32_LE(m + 40));
x11 = XOR(x11, LOAD32_LE(m + 44));
x12 = XOR(x12, LOAD32_LE(m + 48));
x13 = XOR(x13, LOAD32_LE(m + 52));
x14 = XOR(x14, LOAD32_LE(m + 56));
x15 = XOR(x15, LOAD32_LE(m + 60));
*/
$x0 = $x0->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4)));
$x1 = $x1->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 4, 4)));
$x2 = $x2->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 8, 4)));
$x3 = $x3->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4)));
$x4 = $x4->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 16, 4)));
$x5 = $x5->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 20, 4)));
$x6 = $x6->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 24, 4)));
$x7 = $x7->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 28, 4)));
$x8 = $x8->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 32, 4)));
$x9 = $x9->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 36, 4)));
$x10 = $x10->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 40, 4)));
$x11 = $x11->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 44, 4)));
$x12 = $x12->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 48, 4)));
$x13 = $x13->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 52, 4)));
$x14 = $x14->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 56, 4)));
$x15 = $x15->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 60, 4)));
/*
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
}
*/
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
$j12 = $j12->addInt(1);
if ($j12->limbs[0] === 0 && $j12->limbs[1] === 0) {
$j13 = $j13->addInt(1);
}
/*
STORE32_LE(c + 0, x0);
STORE32_LE(c + 4, x1);
STORE32_LE(c + 8, x2);
STORE32_LE(c + 12, x3);
STORE32_LE(c + 16, x4);
STORE32_LE(c + 20, x5);
STORE32_LE(c + 24, x6);
STORE32_LE(c + 28, x7);
STORE32_LE(c + 32, x8);
STORE32_LE(c + 36, x9);
STORE32_LE(c + 40, x10);
STORE32_LE(c + 44, x11);
STORE32_LE(c + 48, x12);
STORE32_LE(c + 52, x13);
STORE32_LE(c + 56, x14);
STORE32_LE(c + 60, x15);
*/
$block = $x0->toReverseString() .
$x1->toReverseString() .
$x2->toReverseString() .
$x3->toReverseString() .
$x4->toReverseString() .
$x5->toReverseString() .
$x6->toReverseString() .
$x7->toReverseString() .
$x8->toReverseString() .
$x9->toReverseString() .
$x10->toReverseString() .
$x11->toReverseString() .
$x12->toReverseString() .
$x13->toReverseString() .
$x14->toReverseString() .
$x15->toReverseString();
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len, $nonce = '', $key = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce, $ic),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce, $ic),
$message
);
}
}
[02-Dec-2025 10:43:07 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Poly1305/State.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core32/Poly1305/State.php on line 10
<?php
if (class_exists('ParagonIE_Sodium_Core32_Poly1305_State', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305_State
*/
class ParagonIE_Sodium_Core32_Poly1305_State extends ParagonIE_Sodium_Core32_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = false;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
public $r;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int64>
*/
public $pad;
/**
* ParagonIE_Sodium_Core32_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Poly1305 requires a 32-byte key'
);
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
// st->r[0] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4))
->setUnsignedInt(true)
->mask(0x3ffffff),
// st->r[1] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 3, 4))
->setUnsignedInt(true)
->shiftRight(2)
->mask(0x3ffff03),
// st->r[2] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 6, 4))
->setUnsignedInt(true)
->shiftRight(4)
->mask(0x3ffc0ff),
// st->r[3] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 9, 4))
->setUnsignedInt(true)
->shiftRight(6)
->mask(0x3f03fff),
// st->r[4] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4))
->setUnsignedInt(true)
->shiftRight(8)
->mask(0x00fffff)
);
/* h = 0 */
$this->h = array(
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true)
);
/* save pad for later */
$this->pad = array(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4))
->setUnsignedInt(true)->toInt64(),
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4))
->setUnsignedInt(true)->toInt64(),
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4))
->setUnsignedInt(true)->toInt64(),
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4))
->setUnsignedInt(true)->toInt64(),
);
$this->leftover = 0;
$this->final = false;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
/* handle leftover */
if ($this->leftover) {
/** @var int $want */
$want = ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - $this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover < ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run $this->blocks()
return $this;
}
$this->blocks(
self::intArrayToString($this->buffer),
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes & ~(ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - 1);
if ($want >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/** @var string $block */
$block = self::substr($message, 0, $want);
if (self::strlen($block) >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = str_pad($message, 16, "\x00", STR_PAD_RIGHT);
}
$hibit = ParagonIE_Sodium_Core32_Int32::fromInt((int) ($this->final ? 0 : 1 << 24)); /* 1 << 128 */
$hibit->setUnsignedInt(true);
$zero = new ParagonIE_Sodium_Core32_Int64(array(0, 0, 0, 0), true);
/**
* @var ParagonIE_Sodium_Core32_Int64 $d0
* @var ParagonIE_Sodium_Core32_Int64 $d1
* @var ParagonIE_Sodium_Core32_Int64 $d2
* @var ParagonIE_Sodium_Core32_Int64 $d3
* @var ParagonIE_Sodium_Core32_Int64 $d4
* @var ParagonIE_Sodium_Core32_Int64 $r0
* @var ParagonIE_Sodium_Core32_Int64 $r1
* @var ParagonIE_Sodium_Core32_Int64 $r2
* @var ParagonIE_Sodium_Core32_Int64 $r3
* @var ParagonIE_Sodium_Core32_Int64 $r4
*
* @var ParagonIE_Sodium_Core32_Int32 $h0
* @var ParagonIE_Sodium_Core32_Int32 $h1
* @var ParagonIE_Sodium_Core32_Int32 $h2
* @var ParagonIE_Sodium_Core32_Int32 $h3
* @var ParagonIE_Sodium_Core32_Int32 $h4
*/
$r0 = $this->r[0]->toInt64();
$r1 = $this->r[1]->toInt64();
$r2 = $this->r[2]->toInt64();
$r3 = $this->r[3]->toInt64();
$r4 = $this->r[4]->toInt64();
$s1 = $r1->toInt64()->mulInt(5, 3);
$s2 = $r2->toInt64()->mulInt(5, 3);
$s3 = $r3->toInt64()->mulInt(5, 3);
$s4 = $r4->toInt64()->mulInt(5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 = $h0->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4))
->mask(0x3ffffff)
)->toInt64();
$h1 = $h1->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 3, 4))
->shiftRight(2)
->mask(0x3ffffff)
)->toInt64();
$h2 = $h2->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 6, 4))
->shiftRight(4)
->mask(0x3ffffff)
)->toInt64();
$h3 = $h3->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 9, 4))
->shiftRight(6)
->mask(0x3ffffff)
)->toInt64();
$h4 = $h4->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4))
->shiftRight(8)
->orInt32($hibit)
)->toInt64();
/* h *= r */
$d0 = $zero
->addInt64($h0->mulInt64($r0, 27))
->addInt64($s4->mulInt64($h1, 27))
->addInt64($s3->mulInt64($h2, 27))
->addInt64($s2->mulInt64($h3, 27))
->addInt64($s1->mulInt64($h4, 27));
$d1 = $zero
->addInt64($h0->mulInt64($r1, 27))
->addInt64($h1->mulInt64($r0, 27))
->addInt64($s4->mulInt64($h2, 27))
->addInt64($s3->mulInt64($h3, 27))
->addInt64($s2->mulInt64($h4, 27));
$d2 = $zero
->addInt64($h0->mulInt64($r2, 27))
->addInt64($h1->mulInt64($r1, 27))
->addInt64($h2->mulInt64($r0, 27))
->addInt64($s4->mulInt64($h3, 27))
->addInt64($s3->mulInt64($h4, 27));
$d3 = $zero
->addInt64($h0->mulInt64($r3, 27))
->addInt64($h1->mulInt64($r2, 27))
->addInt64($h2->mulInt64($r1, 27))
->addInt64($h3->mulInt64($r0, 27))
->addInt64($s4->mulInt64($h4, 27));
$d4 = $zero
->addInt64($h0->mulInt64($r4, 27))
->addInt64($h1->mulInt64($r3, 27))
->addInt64($h2->mulInt64($r2, 27))
->addInt64($h3->mulInt64($r1, 27))
->addInt64($h4->mulInt64($r0, 27));
/* (partial) h %= p */
$c = $d0->shiftRight(26);
$h0 = $d0->toInt32()->mask(0x3ffffff);
$d1 = $d1->addInt64($c);
$c = $d1->shiftRight(26);
$h1 = $d1->toInt32()->mask(0x3ffffff);
$d2 = $d2->addInt64($c);
$c = $d2->shiftRight(26);
$h2 = $d2->toInt32()->mask(0x3ffffff);
$d3 = $d3->addInt64($c);
$c = $d3->shiftRight(26);
$h3 = $d3->toInt32()->mask(0x3ffffff);
$d4 = $d4->addInt64($c);
$c = $d4->shiftRight(26);
$h4 = $d4->toInt32()->mask(0x3ffffff);
$h0 = $h0->addInt32($c->toInt32()->mulInt(5, 3));
$c = $h0->shiftRight(26);
$h0 = $h0->mask(0x3ffffff);
$h1 = $h1->addInt32($c);
// Chop off the left 32 bytes.
$message = self::substr(
$message,
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
);
$bytes -= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE;
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
$this->h = array($h0, $h1, $h2, $h3, $h4);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE; ++$i) {
$this->buffer[$i] = 0;
}
$this->final = true;
$this->blocks(
self::substr(
self::intArrayToString($this->buffer),
0,
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
),
$b = ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
);
}
/**
* @var ParagonIE_Sodium_Core32_Int32 $f
* @var ParagonIE_Sodium_Core32_Int32 $g0
* @var ParagonIE_Sodium_Core32_Int32 $g1
* @var ParagonIE_Sodium_Core32_Int32 $g2
* @var ParagonIE_Sodium_Core32_Int32 $g3
* @var ParagonIE_Sodium_Core32_Int32 $g4
* @var ParagonIE_Sodium_Core32_Int32 $h0
* @var ParagonIE_Sodium_Core32_Int32 $h1
* @var ParagonIE_Sodium_Core32_Int32 $h2
* @var ParagonIE_Sodium_Core32_Int32 $h3
* @var ParagonIE_Sodium_Core32_Int32 $h4
*/
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
$c = $h1->shiftRight(26); # $c = $h1 >> 26;
$h1 = $h1->mask(0x3ffffff); # $h1 &= 0x3ffffff;
$h2 = $h2->addInt32($c); # $h2 += $c;
$c = $h2->shiftRight(26); # $c = $h2 >> 26;
$h2 = $h2->mask(0x3ffffff); # $h2 &= 0x3ffffff;
$h3 = $h3->addInt32($c); # $h3 += $c;
$c = $h3->shiftRight(26); # $c = $h3 >> 26;
$h3 = $h3->mask(0x3ffffff); # $h3 &= 0x3ffffff;
$h4 = $h4->addInt32($c); # $h4 += $c;
$c = $h4->shiftRight(26); # $c = $h4 >> 26;
$h4 = $h4->mask(0x3ffffff); # $h4 &= 0x3ffffff;
$h0 = $h0->addInt32($c->mulInt(5, 3)); # $h0 += self::mul($c, 5);
$c = $h0->shiftRight(26); # $c = $h0 >> 26;
$h0 = $h0->mask(0x3ffffff); # $h0 &= 0x3ffffff;
$h1 = $h1->addInt32($c); # $h1 += $c;
/* compute h + -p */
$g0 = $h0->addInt(5);
$c = $g0->shiftRight(26);
$g0 = $g0->mask(0x3ffffff);
$g1 = $h1->addInt32($c);
$c = $g1->shiftRight(26);
$g1 = $g1->mask(0x3ffffff);
$g2 = $h2->addInt32($c);
$c = $g2->shiftRight(26);
$g2 = $g2->mask(0x3ffffff);
$g3 = $h3->addInt32($c);
$c = $g3->shiftRight(26);
$g3 = $g3->mask(0x3ffffff);
$g4 = $h4->addInt32($c)->subInt(1 << 26);
# $mask = ($g4 >> 31) - 1;
/* select h if h < p, or h + -p if h >= p */
$mask = (int) (($g4->toInt() >> 31) + 1);
$g0 = $g0->mask($mask);
$g1 = $g1->mask($mask);
$g2 = $g2->mask($mask);
$g3 = $g3->mask($mask);
$g4 = $g4->mask($mask);
/** @var int $mask */
$mask = ~$mask;
$h0 = $h0->mask($mask)->orInt32($g0);
$h1 = $h1->mask($mask)->orInt32($g1);
$h2 = $h2->mask($mask)->orInt32($g2);
$h3 = $h3->mask($mask)->orInt32($g3);
$h4 = $h4->mask($mask)->orInt32($g4);
/* h = h % (2^128) */
$h0 = $h0->orInt32($h1->shiftLeft(26));
$h1 = $h1->shiftRight(6)->orInt32($h2->shiftLeft(20));
$h2 = $h2->shiftRight(12)->orInt32($h3->shiftLeft(14));
$h3 = $h3->shiftRight(18)->orInt32($h4->shiftLeft(8));
/* mac = (h + pad) % (2^128) */
$f = $h0->toInt64()->addInt64($this->pad[0]);
$h0 = $f->toInt32();
$f = $h1->toInt64()->addInt64($this->pad[1])->addInt($h0->overflow);
$h1 = $f->toInt32();
$f = $h2->toInt64()->addInt64($this->pad[2])->addInt($h1->overflow);
$h2 = $f->toInt32();
$f = $h3->toInt64()->addInt64($this->pad[3])->addInt($h2->overflow);
$h3 = $f->toInt32();
return $h0->toReverseString() .
$h1->toReverseString() .
$h2->toReverseString() .
$h3->toReverseString();
}
}
<?php
if (!class_exists('SodiumException', false)) {
/**
* Class SodiumException
*/
class SodiumException extends Exception
{
}
}
<?php
/**
* Libsodium compatibility layer
*
* This is the only class you should be interfacing with, as a user of
* sodium_compat.
*
* If the PHP extension for libsodium is installed, it will always use that
* instead of our implementations. You get better performance and stronger
* guarantees against side-channels that way.
*
* However, if your users don't have the PHP extension installed, we offer a
* compatible interface here. It will give you the correct results as if the
* PHP extension was installed. It won't be as fast, of course.
*
* CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
* *
* Until audited, this is probably not safe to use! DANGER WILL ROBINSON *
* *
* CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
*/
if (class_exists('ParagonIE_Sodium_Compat', false)) {
return;
}
class ParagonIE_Sodium_Compat
{
/**
* This parameter prevents the use of the PECL extension.
* It should only be used for unit testing.
*
* @var bool
*/
public static $disableFallbackForUnitTests = false;
/**
* Use fast multiplication rather than our constant-time multiplication
* implementation. Can be enabled at runtime. Only enable this if you
* are absolutely certain that there is no timing leak on your platform.
*
* @var bool
*/
public static $fastMult = false;
const LIBRARY_MAJOR_VERSION = 9;
const LIBRARY_MINOR_VERSION = 1;
const LIBRARY_VERSION_MAJOR = 9;
const LIBRARY_VERSION_MINOR = 1;
const VERSION_STRING = 'polyfill-1.0.8';
// From libsodium
const BASE64_VARIANT_ORIGINAL = 1;
const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
const BASE64_VARIANT_URLSAFE = 5;
const BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
const CRYPTO_AEAD_AES256GCM_ABYTES = 16;
const CRYPTO_AEAD_AEGIS128L_KEYBYTES = 16;
const CRYPTO_AEAD_AEGIS128L_NSECBYTES = 0;
const CRYPTO_AEAD_AEGIS128L_NPUBBYTES = 16;
const CRYPTO_AEAD_AEGIS128L_ABYTES = 32;
const CRYPTO_AEAD_AEGIS256_KEYBYTES = 32;
const CRYPTO_AEAD_AEGIS256_NSECBYTES = 0;
const CRYPTO_AEAD_AEGIS256_NPUBBYTES = 32;
const CRYPTO_AEAD_AEGIS256_ABYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
const CRYPTO_AUTH_BYTES = 32;
const CRYPTO_AUTH_KEYBYTES = 32;
const CRYPTO_BOX_SEALBYTES = 16;
const CRYPTO_BOX_SECRETKEYBYTES = 32;
const CRYPTO_BOX_PUBLICKEYBYTES = 32;
const CRYPTO_BOX_KEYPAIRBYTES = 64;
const CRYPTO_BOX_MACBYTES = 16;
const CRYPTO_BOX_NONCEBYTES = 24;
const CRYPTO_BOX_SEEDBYTES = 32;
const CRYPTO_CORE_RISTRETTO255_BYTES = 32;
const CRYPTO_CORE_RISTRETTO255_SCALARBYTES = 32;
const CRYPTO_CORE_RISTRETTO255_HASHBYTES = 64;
const CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES = 64;
const CRYPTO_KDF_BYTES_MIN = 16;
const CRYPTO_KDF_BYTES_MAX = 64;
const CRYPTO_KDF_CONTEXTBYTES = 8;
const CRYPTO_KDF_KEYBYTES = 32;
const CRYPTO_KX_BYTES = 32;
const CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
const CRYPTO_KX_SEEDBYTES = 32;
const CRYPTO_KX_KEYPAIRBYTES = 64;
const CRYPTO_KX_PUBLICKEYBYTES = 32;
const CRYPTO_KX_SECRETKEYBYTES = 32;
const CRYPTO_KX_SESSIONKEYBYTES = 32;
const CRYPTO_GENERICHASH_BYTES = 32;
const CRYPTO_GENERICHASH_BYTES_MIN = 16;
const CRYPTO_GENERICHASH_BYTES_MAX = 64;
const CRYPTO_GENERICHASH_KEYBYTES = 32;
const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
const CRYPTO_PWHASH_SALTBYTES = 16;
const CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
const CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$';
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824;
const CRYPTO_SCALARMULT_BYTES = 32;
const CRYPTO_SCALARMULT_SCALARBYTES = 32;
const CRYPTO_SCALARMULT_RISTRETTO255_BYTES = 32;
const CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES = 32;
const CRYPTO_SHORTHASH_BYTES = 8;
const CRYPTO_SHORTHASH_KEYBYTES = 16;
const CRYPTO_SECRETBOX_KEYBYTES = 32;
const CRYPTO_SECRETBOX_MACBYTES = 16;
const CRYPTO_SECRETBOX_NONCEBYTES = 24;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
const CRYPTO_SIGN_BYTES = 64;
const CRYPTO_SIGN_SEEDBYTES = 32;
const CRYPTO_SIGN_PUBLICKEYBYTES = 32;
const CRYPTO_SIGN_SECRETKEYBYTES = 64;
const CRYPTO_SIGN_KEYPAIRBYTES = 96;
const CRYPTO_STREAM_KEYBYTES = 32;
const CRYPTO_STREAM_NONCEBYTES = 24;
const CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32;
const CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24;
/**
* Add two numbers (little-endian unsigned), storing the value in the first
* parameter.
*
* This mutates $val.
*
* @param string $val
* @param string $addv
* @return void
* @throws SodiumException
*/
public static function add(
#[\SensitiveParameter]
&$val,
#[\SensitiveParameter]
$addv
) {
$val_len = ParagonIE_Sodium_Core_Util::strlen($val);
$addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
if ($val_len !== $addv_len) {
throw new SodiumException('values must have the same length');
}
$A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
$B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
$c = 0;
for ($i = 0; $i < $val_len; $i++) {
$c += ($A[$i] + $B[$i]);
$A[$i] = ($c & 0xff);
$c >>= 8;
}
$val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
}
/**
* @param string $encoded
* @param int $variant
* @param string $ignore
* @return string
* @throws SodiumException
*/
public static function base642bin(
#[\SensitiveParameter]
$encoded,
$variant,
$ignore = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($encoded, 'string', 1);
/** @var string $encoded */
$encoded = (string) $encoded;
if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) {
return '';
}
// Just strip before decoding
if (!empty($ignore)) {
$encoded = str_replace($ignore, '', $encoded);
}
try {
switch ($variant) {
case self::BASE64_VARIANT_ORIGINAL:
return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true);
case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false);
case self::BASE64_VARIANT_URLSAFE:
return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true);
case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false);
default:
throw new SodiumException('invalid base64 variant identifier');
}
} catch (Exception $ex) {
if ($ex instanceof SodiumException) {
throw $ex;
}
throw new SodiumException('invalid base64 string');
}
}
/**
* @param string $decoded
* @param int $variant
* @return string
* @throws SodiumException
*/
public static function bin2base64(
#[\SensitiveParameter]
$decoded,
$variant
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($decoded, 'string', 1);
/** @var string $decoded */
$decoded = (string) $decoded;
if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) {
return '';
}
switch ($variant) {
case self::BASE64_VARIANT_ORIGINAL:
return ParagonIE_Sodium_Core_Base64_Original::encode($decoded);
case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
return ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded);
case self::BASE64_VARIANT_URLSAFE:
return ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded);
case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
return ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded);
default:
throw new SodiumException('invalid base64 variant identifier');
}
}
/**
* Cache-timing-safe implementation of bin2hex().
*
* @param string $string A string (probably raw binary)
* @return string A hexadecimal-encoded string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function bin2hex(
#[\SensitiveParameter]
$string
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
if (self::useNewSodiumAPI()) {
return (string) sodium_bin2hex($string);
}
if (self::use_fallback('bin2hex')) {
return (string) call_user_func('\\Sodium\\bin2hex', $string);
}
return ParagonIE_Sodium_Core_Util::bin2hex($string);
}
/**
* Compare two strings, in constant-time.
* Compared to memcmp(), compare() is more useful for sorting.
*
* @param string $left The left operand; must be a string
* @param string $right The right operand; must be a string
* @return int If < 0 if the left operand is less than the right
* If = 0 if both strings are equal
* If > 0 if the right operand is less than the left
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function compare(
#[\SensitiveParameter]
$left,
#[\SensitiveParameter]
$right
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
if (self::useNewSodiumAPI()) {
return (int) sodium_compare($left, $right);
}
if (self::use_fallback('compare')) {
return (int) call_user_func('\\Sodium\\compare', $left, $right);
}
return ParagonIE_Sodium_Core_Util::compare($left, $right);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* AEGIS-128L
*
* @param string $ciphertext Encrypted message (with MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aegis128l_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS_128L_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
$ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext);
if ($ct_length < self::CRYPTO_AEAD_AEGIS128L_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS128L_ABYTES long');
}
$ct = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
$ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES
);
$tag = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
$ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES,
self::CRYPTO_AEAD_AEGIS128L_ABYTES
);
return ParagonIE_Sodium_Core_AEGIS128L::decrypt($ct, $tag, $assocData, $key, $nonce);
}
/**
* Authenticated Encryption with Associated Data: Encryption
*
* Algorithm:
* AEGIS-128L
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with 32-byte authentication tag appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_aegis128l_encrypt(
#[\SensitiveParameter]
$plaintext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS128L::encrypt($plaintext, $assocData, $key, $nonce);
return $ct . $tag;
}
/**
* Return a secure random key for use with the AEGIS-128L
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_aegis128l_keygen()
{
return random_bytes(self::CRYPTO_AEAD_AEGIS128L_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* AEGIS-256
*
* @param string $ciphertext Encrypted message (with MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aegis256_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS256_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS256_KEYBYTES long');
}
$ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext);
if ($ct_length < self::CRYPTO_AEAD_AEGIS256_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS256_ABYTES long');
}
$ct = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
$ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES
);
$tag = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
$ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES,
self::CRYPTO_AEAD_AEGIS256_ABYTES
);
return ParagonIE_Sodium_Core_AEGIS256::decrypt($ct, $tag, $assocData, $key, $nonce);
}
/**
* Authenticated Encryption with Associated Data: Encryption
*
* Algorithm:
* AEGIS-256
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 32 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with 32-byte authentication tag appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_aegis256_encrypt(
#[\SensitiveParameter]
$plaintext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long');
}
list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS256::encrypt($plaintext, $assocData, $key, $nonce);
return $ct . $tag;
}
/**
* Return a secure random key for use with the AEGIS-256
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_aegis256_keygen()
{
return random_bytes(self::CRYPTO_AEAD_AEGIS256_KEYBYTES);
}
/**
* Is AES-256-GCM even available to use?
*
* @return bool
* @psalm-suppress UndefinedFunction
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aes256gcm_is_available()
{
if (self::useNewSodiumAPI()) {
return sodium_crypto_aead_aes256gcm_is_available();
}
if (self::use_fallback('crypto_aead_aes256gcm_is_available')) {
return call_user_func('\\Sodium\\crypto_aead_aes256gcm_is_available');
}
if (PHP_VERSION_ID < 70100) {
// OpenSSL doesn't support AEAD before 7.1.0
return false;
}
if (!is_callable('openssl_encrypt') || !is_callable('openssl_decrypt')) {
// OpenSSL isn't installed
return false;
}
return (bool) in_array('aes-256-gcm', openssl_get_cipher_methods());
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* AES-256-GCM
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
*
* @return string|bool The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aes256gcm_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
if (!self::crypto_aead_aes256gcm_is_available()) {
throw new SodiumException('AES-256-GCM is not available');
}
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_AES256GCM_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_AES256GCM_ABYTES long');
}
if (!is_callable('openssl_decrypt')) {
throw new SodiumException('The OpenSSL extension is not installed, or openssl_decrypt() is not available');
}
/** @var string $ctext */
$ctext = ParagonIE_Sodium_Core_Util::substr($ciphertext, 0, -self::CRYPTO_AEAD_AES256GCM_ABYTES);
/** @var string $authTag */
$authTag = ParagonIE_Sodium_Core_Util::substr($ciphertext, -self::CRYPTO_AEAD_AES256GCM_ABYTES, 16);
return openssl_decrypt(
$ctext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$nonce,
$authTag,
$assocData
);
}
/**
* Authenticated Encryption with Associated Data: Encryption
*
* Algorithm:
* AES-256-GCM
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with a 16-byte GCM message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_aes256gcm_encrypt(
#[\SensitiveParameter]
$plaintext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
if (!self::crypto_aead_aes256gcm_is_available()) {
throw new SodiumException('AES-256-GCM is not available');
}
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long');
}
if (!is_callable('openssl_encrypt')) {
throw new SodiumException('The OpenSSL extension is not installed, or openssl_encrypt() is not available');
}
$authTag = '';
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$nonce,
$authTag,
$assocData
);
return $ciphertext . $authTag;
}
/**
* Return a secure random key for use with the AES-256-GCM
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_aes256gcm_keygen()
{
return random_bytes(self::CRYPTO_AEAD_AES256GCM_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* ChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_chacha20poly1305_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_aead_chacha20poly1305_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) {
return call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_decrypt',
$ciphertext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
/**
* Authenticated Encryption with Associated Data
*
* Algorithm:
* ChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with a 16-byte Poly1305 message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_chacha20poly1305_encrypt(
#[\SensitiveParameter]
$plaintext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_aead_chacha20poly1305_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) {
return (string) call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_encrypt',
$plaintext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* ChaCha20-Poly1305
*
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
* Regular mode uses a 64-bit random nonce with a 64-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 12 bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_chacha20poly1305_ietf_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_aead_chacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) {
return call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt',
$ciphertext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
/**
* Return a secure random key for use with the ChaCha20-Poly1305
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_chacha20poly1305_keygen()
{
return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data
*
* Algorithm:
* ChaCha20-Poly1305
*
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
* Regular mode uses a 64-bit random nonce with a 64-bit counter.
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with a 16-byte Poly1305 message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_chacha20poly1305_ietf_encrypt(
#[\SensitiveParameter]
$plaintext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
if (!is_null($assocData)) {
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
}
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_aead_chacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) {
return (string) call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt',
$plaintext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
/**
* Return a secure random key for use with the ChaCha20-Poly1305
* symmetric AEAD interface. (IETF version)
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_chacha20poly1305_ietf_keygen()
{
return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* XChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
* @param bool $dontFallback Don't fallback to ext/sodium
*
* @return string|bool The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_xchacha20poly1305_ietf_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = '',
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
if (!is_null($assocData)) {
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
} else {
$assocData = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) {
throw new SodiumException('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) {
return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
/**
* Authenticated Encryption with Associated Data
*
* Algorithm:
* XChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
* @param bool $dontFallback Don't fallback to ext/sodium
*
* @return string Ciphertext with a 16-byte Poly1305 message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_xchacha20poly1305_ietf_encrypt(
#[\SensitiveParameter]
$plaintext = '',
$assocData = '',
$nonce = '',
#[\SensitiveParameter]
$key = '',
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
if (!is_null($assocData)) {
ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
} else {
$assocData = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) {
return sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
/**
* Return a secure random key for use with the XChaCha20-Poly1305
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_xchacha20poly1305_ietf_keygen()
{
return random_bytes(self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES);
}
/**
* Authenticate a message. Uses symmetric-key cryptography.
*
* Algorithm:
* HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits.
* Not to be confused with HMAC-SHA-512/256 which would use the
* SHA-512/256 hash function (uses different initial parameters
* but still truncates to 256 bits to sidestep length-extension
* attacks).
*
* @param string $message Message to be authenticated
* @param string $key Symmetric authentication key
* @return string Message authentication code
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_auth(
$message,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_auth($message, $key);
}
if (self::use_fallback('crypto_auth')) {
return (string) call_user_func('\\Sodium\\crypto_auth', $message, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::auth($message, $key);
}
return ParagonIE_Sodium_Crypto::auth($message, $key);
}
/**
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_auth_keygen()
{
return random_bytes(self::CRYPTO_AUTH_KEYBYTES);
}
/**
* Verify the MAC of a message previously authenticated with crypto_auth.
*
* @param string $mac Message authentication code
* @param string $message Message whose authenticity you are attempting to
* verify (with a given MAC and key)
* @param string $key Symmetric authentication key
* @return bool TRUE if authenticated, FALSE otherwise
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_auth_verify(
$mac,
$message,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($mac, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_AUTH_BYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_auth_verify($mac, $message, $key);
}
if (self::use_fallback('crypto_auth_verify')) {
return (bool) call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message, $key);
}
return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key);
}
/**
* Authenticated asymmetric-key encryption. Both the sender and recipient
* may decrypt messages.
*
* Algorithm: X25519-XSalsa20-Poly1305.
* X25519: Elliptic-Curve Diffie Hellman over Curve25519.
* XSalsa20: Extended-nonce variant of salsa20.
* Poyl1305: Polynomial MAC for one-time message authentication.
*
* @param string $plaintext The message to be encrypted
* @param string $nonce A Number to only be used Once; must be 24 bytes
* @param string $keypair Your secret key and your recipient's public key
* @return string Ciphertext with 16-byte Poly1305 MAC
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box(
$plaintext,
$nonce,
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box($plaintext, $nonce, $keypair);
}
if (self::use_fallback('crypto_box')) {
return (string) call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce, $keypair);
}
return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair);
}
/**
* Anonymous public-key encryption. Only the recipient may decrypt messages.
*
* Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box.
* The sender's X25519 keypair is ephemeral.
* Nonce is generated from the BLAKE2b hash of both public keys.
*
* This provides ciphertext integrity.
*
* @param string $plaintext Message to be sealed
* @param string $publicKey Your recipient's public key
* @return string Sealed message that only your recipient can
* decrypt
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_seal(
#[\SensitiveParameter]
$plaintext,
$publicKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_seal($plaintext, $publicKey);
}
if (self::use_fallback('crypto_box_seal')) {
return (string) call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_seal($plaintext, $publicKey);
}
return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey);
}
/**
* Opens a message encrypted with crypto_box_seal(). Requires
* the recipient's keypair (sk || pk) to decrypt successfully.
*
* This validates ciphertext integrity.
*
* @param string $ciphertext Sealed message to be opened
* @param string $keypair Your crypto_box keypair
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_box_seal_open(
$ciphertext,
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_box_seal_open($ciphertext, $keypair);
}
if (self::use_fallback('crypto_box_seal_open')) {
return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext, $keypair);
}
return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair);
}
/**
* Generate a new random X25519 keypair.
*
* @return string A 64-byte string; the first 32 are your secret key, while
* the last 32 are your public key. crypto_box_secretkey()
* and crypto_box_publickey() exist to separate them so you
* don't accidentally get them mixed up!
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_keypair()
{
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_keypair();
}
if (self::use_fallback('crypto_box_keypair')) {
return (string) call_user_func('\\Sodium\\crypto_box_keypair');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_keypair();
}
return ParagonIE_Sodium_Crypto::box_keypair();
}
/**
* Combine two keys into a keypair for use in library methods that expect
* a keypair. This doesn't necessarily have to be the same person's keys.
*
* @param string $secretKey Secret key
* @param string $publicKey Public key
* @return string Keypair
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_keypair_from_secretkey_and_publickey(
#[\SensitiveParameter]
$secretKey,
$publicKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
}
if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) {
return (string) call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
}
return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
}
/**
* Decrypt a message previously encrypted with crypto_box().
*
* @param string $ciphertext Encrypted message
* @param string $nonce Number to only be used Once; must be 24 bytes
* @param string $keypair Your secret key and the sender's public key
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_box_open(
$ciphertext,
$nonce,
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) {
throw new SodiumException('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_box_open($ciphertext, $nonce, $keypair);
}
if (self::use_fallback('crypto_box_open')) {
return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce, $keypair);
}
return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair);
}
/**
* Extract the public key from a crypto_box keypair.
*
* @param string $keypair Keypair containing secret and public key
* @return string Your crypto_box public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_publickey(
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_publickey($keypair);
}
if (self::use_fallback('crypto_box_publickey')) {
return (string) call_user_func('\\Sodium\\crypto_box_publickey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_publickey($keypair);
}
return ParagonIE_Sodium_Crypto::box_publickey($keypair);
}
/**
* Calculate the X25519 public key from a given X25519 secret key.
*
* @param string $secretKey Any X25519 secret key
* @return string The corresponding X25519 public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_publickey_from_secretkey(
#[\SensitiveParameter]
$secretKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_publickey_from_secretkey($secretKey);
}
if (self::use_fallback('crypto_box_publickey_from_secretkey')) {
return (string) call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey);
}
return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey);
}
/**
* Extract the secret key from a crypto_box keypair.
*
* @param string $keypair
* @return string Your crypto_box secret key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_secretkey(
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_secretkey($keypair);
}
if (self::use_fallback('crypto_box_secretkey')) {
return (string) call_user_func('\\Sodium\\crypto_box_secretkey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_secretkey($keypair);
}
return ParagonIE_Sodium_Crypto::box_secretkey($keypair);
}
/**
* Generate an X25519 keypair from a seed.
*
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress UndefinedFunction
*/
public static function crypto_box_seed_keypair(
#[\SensitiveParameter]
$seed
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_seed_keypair($seed);
}
if (self::use_fallback('crypto_box_seed_keypair')) {
return (string) call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_seed_keypair($seed);
}
return ParagonIE_Sodium_Crypto::box_seed_keypair($seed);
}
/**
* Calculates a BLAKE2b hash, with an optional key.
*
* @param string $message The message to be hashed
* @param string|null $key If specified, must be a string between 16
* and 64 bytes long
* @param int $length Output length in bytes; must be between 16
* and 64 (default = 32)
* @return string Raw binary
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_generichash(
$message,
#[\SensitiveParameter]
$key = '',
$length = self::CRYPTO_GENERICHASH_BYTES
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
if (is_null($key)) {
$key = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 3);
/* Input validation: */
if (!empty($key)) {
if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
}
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_generichash($message, $key, $length);
}
if (self::use_fallback('crypto_generichash')) {
return (string) call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::generichash($message, $key, $length);
}
return ParagonIE_Sodium_Crypto::generichash($message, $key, $length);
}
/**
* Get the final BLAKE2b hash output for a given context.
*
* @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init().
* @param int $length Hash output size.
* @return string Final BLAKE2b hash.
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress ReferenceConstraintViolation
* @psalm-suppress ConflictingReferenceConstraint
*/
public static function crypto_generichash_final(
#[\SensitiveParameter]
&$ctx,
$length = self::CRYPTO_GENERICHASH_BYTES
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
if (self::useNewSodiumAPI()) {
return sodium_crypto_generichash_final($ctx, $length);
}
if (self::use_fallback('crypto_generichash_final')) {
$func = '\\Sodium\\crypto_generichash_final';
return (string) $func($ctx, $length);
}
if ($length < 1) {
try {
self::memzero($ctx);
} catch (SodiumException $ex) {
unset($ctx);
}
return '';
}
if (PHP_INT_SIZE === 4) {
$result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length);
} else {
$result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length);
}
try {
self::memzero($ctx);
} catch (SodiumException $ex) {
unset($ctx);
}
return $result;
}
/**
* Initialize a BLAKE2b hashing context, for use in a streaming interface.
*
* @param string|null $key If specified must be a string between 16 and 64 bytes
* @param int $length The size of the desired hash output
* @return string A BLAKE2 hashing context, encoded as a string
* (To be 100% compatible with ext/libsodium)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_generichash_init(
#[\SensitiveParameter]
$key = '',
$length = self::CRYPTO_GENERICHASH_BYTES
) {
/* Type checks: */
if (is_null($key)) {
$key = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
/* Input validation: */
if (!empty($key)) {
if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
}
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_generichash_init($key, $length);
}
if (self::use_fallback('crypto_generichash_init')) {
return (string) call_user_func('\\Sodium\\crypto_generichash_init', $key, $length);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::generichash_init($key, $length);
}
return ParagonIE_Sodium_Crypto::generichash_init($key, $length);
}
/**
* Initialize a BLAKE2b hashing context, for use in a streaming interface.
*
* @param string|null $key If specified must be a string between 16 and 64 bytes
* @param int $length The size of the desired hash output
* @param string $salt Salt (up to 16 bytes)
* @param string $personal Personalization string (up to 16 bytes)
* @return string A BLAKE2 hashing context, encoded as a string
* (To be 100% compatible with ext/libsodium)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_generichash_init_salt_personal(
#[\SensitiveParameter]
$key = '',
$length = self::CRYPTO_GENERICHASH_BYTES,
$salt = '',
$personal = ''
) {
/* Type checks: */
if (is_null($key)) {
$key = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($personal, 'string', 4);
$salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT);
$personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT);
/* Input validation: */
if (!empty($key)) {
/*
if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
}
*/
if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
}
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length, $salt, $personal);
}
return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal);
}
/**
* Update a BLAKE2b hashing context with additional data.
*
* @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init().
* $ctx is passed by reference and gets updated in-place.
* @param-out string $ctx
* @param string $message The message to append to the existing hash state.
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress ReferenceConstraintViolation
*/
public static function crypto_generichash_update(
#[\SensitiveParameter]
&$ctx,
$message
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
if (self::useNewSodiumAPI()) {
sodium_crypto_generichash_update($ctx, $message);
return;
}
if (self::use_fallback('crypto_generichash_update')) {
$func = '\\Sodium\\crypto_generichash_update';
$func($ctx, $message);
return;
}
if (PHP_INT_SIZE === 4) {
$ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx, $message);
} else {
$ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message);
}
}
/**
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_generichash_keygen()
{
return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES);
}
/**
* @param int $subkey_len
* @param int $subkey_id
* @param string $context
* @param string $key
* @return string
* @throws SodiumException
*/
public static function crypto_kdf_derive_from_key(
$subkey_len,
$subkey_id,
$context,
#[\SensitiveParameter]
$key
) {
ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len, 'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($context, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
$subkey_id = (int) $subkey_id;
$subkey_len = (int) $subkey_len;
$context = (string) $context;
$key = (string) $key;
if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) {
throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN');
}
if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) {
throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX');
}
if ($subkey_id < 0) {
throw new SodiumException('subkey_id cannot be negative');
}
if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) {
throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) {
throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes');
}
$salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id);
$state = self::crypto_generichash_init_salt_personal(
$key,
$subkey_len,
$salt,
$context
);
return self::crypto_generichash_final($state, $subkey_len);
}
/**
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_kdf_keygen()
{
return random_bytes(self::CRYPTO_KDF_KEYBYTES);
}
/**
* Perform a key exchange, between a designated client and a server.
*
* Typically, you would designate one machine to be the client and the
* other to be the server. The first two keys are what you'd expect for
* scalarmult() below, but the latter two public keys don't swap places.
*
* | ALICE | BOB |
* | Client | Server |
* |--------------------------------|-------------------------------------|
* | shared = crypto_kx( | shared = crypto_kx( |
* | alice_sk, | bob_sk, | <- contextual
* | bob_pk, | alice_pk, | <- contextual
* | alice_pk, | alice_pk, | <----- static
* | bob_pk | bob_pk | <----- static
* | ) | ) |
*
* They are used along with the scalarmult product to generate a 256-bit
* BLAKE2b hash unique to the client and server keys.
*
* @param string $my_secret
* @param string $their_public
* @param string $client_public
* @param string $server_public
* @param bool $dontFallback
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_kx(
#[\SensitiveParameter]
$my_secret,
$their_public,
$client_public,
$server_public,
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($my_secret, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($their_public, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($client_public, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($server_public, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
if (is_callable('sodium_crypto_kx')) {
return (string) sodium_crypto_kx(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
}
if (self::use_fallback('crypto_kx')) {
return (string) call_user_func(
'\\Sodium\\crypto_kx',
$my_secret,
$their_public,
$client_public,
$server_public
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::keyExchange(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
return ParagonIE_Sodium_Crypto::keyExchange(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
/**
* @param string $seed
* @return string
* @throws SodiumException
*/
public static function crypto_kx_seed_keypair(
#[\SensitiveParameter]
$seed
) {
ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
$seed = (string) $seed;
if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) {
throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes');
}
$sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES);
$pk = self::crypto_scalarmult_base($sk);
return $sk . $pk;
}
/**
* @return string
* @throws Exception
*/
public static function crypto_kx_keypair()
{
$sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES);
$pk = self::crypto_scalarmult_base($sk);
return $sk . $pk;
}
/**
* @param string $keypair
* @param string $serverPublicKey
* @return array{0: string, 1: string}
* @throws SodiumException
*/
public static function crypto_kx_client_session_keys(
#[\SensitiveParameter]
$keypair,
$serverPublicKey
) {
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey, 'string', 2);
$keypair = (string) $keypair;
$serverPublicKey = (string) $serverPublicKey;
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
}
$sk = self::crypto_kx_secretkey($keypair);
$pk = self::crypto_kx_publickey($keypair);
$h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey));
self::crypto_generichash_update($h, $pk);
self::crypto_generichash_update($h, $serverPublicKey);
$sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
return array(
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
0,
self::CRYPTO_KX_SESSIONKEYBYTES
),
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
self::CRYPTO_KX_SESSIONKEYBYTES,
self::CRYPTO_KX_SESSIONKEYBYTES
)
);
}
/**
* @param string $keypair
* @param string $clientPublicKey
* @return array{0: string, 1: string}
* @throws SodiumException
*/
public static function crypto_kx_server_session_keys(
#[\SensitiveParameter]
$keypair,
$clientPublicKey
) {
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey, 'string', 2);
$keypair = (string) $keypair;
$clientPublicKey = (string) $clientPublicKey;
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
}
$sk = self::crypto_kx_secretkey($keypair);
$pk = self::crypto_kx_publickey($keypair);
$h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey));
self::crypto_generichash_update($h, $clientPublicKey);
self::crypto_generichash_update($h, $pk);
$sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
return array(
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
self::CRYPTO_KX_SESSIONKEYBYTES,
self::CRYPTO_KX_SESSIONKEYBYTES
),
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
0,
self::CRYPTO_KX_SESSIONKEYBYTES
)
);
}
/**
* @param string $kp
* @return string
* @throws SodiumException
*/
public static function crypto_kx_secretkey(
#[\SensitiveParameter]
$kp
) {
return ParagonIE_Sodium_Core_Util::substr(
$kp,
0,
self::CRYPTO_KX_SECRETKEYBYTES
);
}
/**
* @param string $kp
* @return string
* @throws SodiumException
*/
public static function crypto_kx_publickey($kp)
{
return ParagonIE_Sodium_Core_Util::substr(
$kp,
self::CRYPTO_KX_SECRETKEYBYTES,
self::CRYPTO_KX_PUBLICKEYBYTES
);
}
/**
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @param int|null $alg
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_pwhash(
$outlen,
#[\SensitiveParameter]
$passwd,
$salt,
$opslimit,
$memlimit,
$alg = null
) {
ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
if (self::useNewSodiumAPI()) {
if (!is_null($alg)) {
ParagonIE_Sodium_Core_Util::declareScalarType($alg, 'int', 6);
return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg);
}
return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit);
}
if (self::use_fallback('crypto_pwhash')) {
return (string) call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
);
}
/**
* !Exclusive to sodium_compat!
*
* This returns TRUE if the native crypto_pwhash API is available by libsodium.
* This returns FALSE if only sodium_compat is available.
*
* @return bool
*/
public static function crypto_pwhash_is_available()
{
if (self::useNewSodiumAPI()) {
return true;
}
if (self::use_fallback('crypto_pwhash')) {
return true;
}
return false;
}
/**
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_pwhash_str(
#[\SensitiveParameter]
$passwd,
$opslimit,
$memlimit
) {
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
if (self::useNewSodiumAPI()) {
return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit);
}
if (self::use_fallback('crypto_pwhash_str')) {
return (string) call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
);
}
/**
* Do we need to rehash this password?
*
* @param string $hash
* @param int $opslimit
* @param int $memlimit
* @return bool
* @throws SodiumException
*/
public static function crypto_pwhash_str_needs_rehash(
#[\SensitiveParameter]
$hash,
$opslimit,
$memlimit
) {
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
// Just grab the first 4 pieces.
$pieces = explode('$', (string) $hash);
$prefix = implode('$', array_slice($pieces, 0, 4));
// Rebuild the expected header.
/** @var int $ops */
$ops = (int) $opslimit;
/** @var int $mem */
$mem = (int) $memlimit >> 10;
$encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1';
// Do they match? If so, we don't need to rehash, so return false.
return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix);
}
/**
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_pwhash_str_verify(
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$hash
) {
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_pwhash_str_verify($passwd, $hash);
}
if (self::use_fallback('crypto_pwhash_str_verify')) {
return (bool) call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
);
}
/**
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_pwhash_scryptsalsa208sha256(
$outlen,
#[\SensitiveParameter]
$passwd,
$salt,
$opslimit,
$memlimit
) {
ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_pwhash_scryptsalsa208sha256(
(int) $outlen,
(string) $passwd,
(string) $salt,
(int) $opslimit,
(int) $memlimit
);
}
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
return (string) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256',
(int) $outlen,
(string) $passwd,
(string) $salt,
(int) $opslimit,
(int) $memlimit
);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
);
}
/**
* !Exclusive to sodium_compat!
*
* This returns TRUE if the native crypto_pwhash API is available by libsodium.
* This returns FALSE if only sodium_compat is available.
*
* @return bool
*/
public static function crypto_pwhash_scryptsalsa208sha256_is_available()
{
if (self::useNewSodiumAPI()) {
return true;
}
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
return true;
}
return false;
}
/**
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_pwhash_scryptsalsa208sha256_str(
#[\SensitiveParameter]
$passwd,
$opslimit,
$memlimit
) {
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_pwhash_scryptsalsa208sha256_str(
(string) $passwd,
(int) $opslimit,
(int) $memlimit
);
}
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) {
return (string) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str',
(string) $passwd,
(int) $opslimit,
(int) $memlimit
);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
);
}
/**
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_pwhash_scryptsalsa208sha256_str_verify(
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$hash
) {
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_pwhash_scryptsalsa208sha256_str_verify(
(string) $passwd,
(string) $hash
);
}
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) {
return (bool) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify',
(string) $passwd,
(string) $hash
);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
);
}
/**
* Calculate the shared secret between your secret key and your
* recipient's public key.
*
* Algorithm: X25519 (ECDH over Curve25519)
*
* @param string $secretKey
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_scalarmult(
#[\SensitiveParameter]
$secretKey,
$publicKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_scalarmult($secretKey, $publicKey);
}
if (self::use_fallback('crypto_scalarmult')) {
return (string) call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey);
}
/* Output validation: Forbid all-zero keys */
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
throw new SodiumException('Zero secret key is not allowed');
}
if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) {
throw new SodiumException('Zero public key is not allowed');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey);
}
return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey);
}
/**
* Calculate an X25519 public key from an X25519 secret key.
*
* @param string $secretKey
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress TooFewArguments
* @psalm-suppress MixedArgument
*/
public static function crypto_scalarmult_base(
#[\SensitiveParameter]
$secretKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_scalarmult_base($secretKey);
}
if (self::use_fallback('crypto_scalarmult_base')) {
return (string) call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey);
}
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
throw new SodiumException('Zero secret key is not allowed');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey);
}
return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey);
}
/**
* Authenticated symmetric-key encryption.
*
* Algorithm: XSalsa20-Poly1305
*
* @param string $plaintext The message you're encrypting
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Ciphertext with Poly1305 MAC
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_secretbox(
#[\SensitiveParameter]
$plaintext,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_secretbox($plaintext, $nonce, $key);
}
if (self::use_fallback('crypto_secretbox')) {
return (string) call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key);
}
return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key);
}
/**
* Decrypts a message previously encrypted with crypto_secretbox().
*
* @param string $ciphertext Ciphertext with Poly1305 MAC
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_secretbox_open(
$ciphertext,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
}
if (self::use_fallback('crypto_secretbox_open')) {
return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key);
}
return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key);
}
/**
* Return a secure random key for use with crypto_secretbox
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_secretbox_keygen()
{
return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES);
}
/**
* Authenticated symmetric-key encryption.
*
* Algorithm: XChaCha20-Poly1305
*
* @param string $plaintext The message you're encrypting
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Ciphertext with Poly1305 MAC
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
}
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
}
/**
* Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305().
*
* @param string $ciphertext Ciphertext with Poly1305 MAC
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_secretbox_xchacha20poly1305_open(
$ciphertext,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
}
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
}
/**
* @param string $key
* @return array<int, string> Returns a state and a header.
* @throws Exception
* @throws SodiumException
*/
public static function crypto_secretstream_xchacha20poly1305_init_push(
#[\SensitiveParameter]
$key
) {
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key);
}
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key);
}
/**
* @param string $header
* @param string $key
* @return string Returns a state.
* @throws Exception
*/
public static function crypto_secretstream_xchacha20poly1305_init_pull(
$header,
#[\SensitiveParameter]
$key
) {
if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
throw new SodiumException(
'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes'
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header);
}
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header);
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
public static function crypto_secretstream_xchacha20poly1305_push(
#[\SensitiveParameter]
&$state,
#[\SensitiveParameter]
$msg,
$aad = '',
$tag = 0
) {
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push(
$state,
$msg,
$aad,
$tag
);
}
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push(
$state,
$msg,
$aad,
$tag
);
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
public static function crypto_secretstream_xchacha20poly1305_pull(
#[\SensitiveParameter]
&$state,
$msg,
$aad = ''
) {
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull(
$state,
$msg,
$aad
);
}
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull(
$state,
$msg,
$aad
);
}
/**
* @return string
* @throws Exception
*/
public static function crypto_secretstream_xchacha20poly1305_keygen()
{
return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES);
}
/**
* @param string $state
* @return void
* @throws SodiumException
*/
public static function crypto_secretstream_xchacha20poly1305_rekey(
#[\SensitiveParameter]
&$state
) {
if (PHP_INT_SIZE === 4) {
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state);
} else {
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state);
}
}
/**
* Calculates a SipHash-2-4 hash of a message for a given key.
*
* @param string $message Input message
* @param string $key SipHash-2-4 key
* @return string Hash
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_shorthash(
$message,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_shorthash($message, $key);
}
if (self::use_fallback('crypto_shorthash')) {
return (string) call_user_func('\\Sodium\\crypto_shorthash', $message, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_SipHash::sipHash24($message, $key);
}
return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key);
}
/**
* Return a secure random key for use with crypto_shorthash
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_shorthash_keygen()
{
return random_bytes(self::CRYPTO_SHORTHASH_KEYBYTES);
}
/**
* Returns a signed message. You probably want crypto_sign_detached()
* instead, which only returns the signature.
*
* Algorithm: Ed25519 (EdDSA over Curve25519)
*
* @param string $message Message to be signed.
* @param string $secretKey Secret signing key.
* @return string Signed message (signature is prefixed).
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_sign(
$message,
#[\SensitiveParameter]
$secretKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign($message, $secretKey);
}
if (self::use_fallback('crypto_sign')) {
return (string) call_user_func('\\Sodium\\crypto_sign', $message, $secretKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign($message, $secretKey);
}
return ParagonIE_Sodium_Crypto::sign($message, $secretKey);
}
/**
* Validates a signed message then returns the message.
*
* @param string $signedMessage A signed message
* @param string $publicKey A public key
* @return string The original message (if the signature is
* valid for this public key)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_sign_open(
$signedMessage,
$publicKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) {
throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_BYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_sign_open($signedMessage, $publicKey);
}
if (self::use_fallback('crypto_sign_open')) {
return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign_open($signedMessage, $publicKey);
}
return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey);
}
/**
* Generate a new random Ed25519 keypair.
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_sign_keypair()
{
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_keypair();
}
if (self::use_fallback('crypto_sign_keypair')) {
return (string) call_user_func('\\Sodium\\crypto_sign_keypair');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::keypair();
}
return ParagonIE_Sodium_Core_Ed25519::keypair();
}
/**
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
*/
public static function crypto_sign_keypair_from_secretkey_and_publickey(
#[\SensitiveParameter]
$sk,
$pk
) {
ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1);
$sk = (string) $sk;
$pk = (string) $pk;
if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
}
return $sk . $pk;
}
/**
* Generate an Ed25519 keypair from a seed.
*
* @param string $seed Input seed
* @return string Keypair
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_seed_keypair(
#[\SensitiveParameter]
$seed
) {
ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_seed_keypair($seed);
}
if (self::use_fallback('crypto_sign_keypair')) {
return (string) call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed);
}
$publicKey = '';
$secretKey = '';
if (PHP_INT_SIZE === 4) {
ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey, $secretKey, $seed);
} else {
ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed);
}
return $secretKey . $publicKey;
}
/**
* Extract an Ed25519 public key from an Ed25519 keypair.
*
* @param string $keypair Keypair
* @return string Public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_publickey(
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_publickey($keypair);
}
if (self::use_fallback('crypto_sign_publickey')) {
return (string) call_user_func('\\Sodium\\crypto_sign_publickey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair);
}
return ParagonIE_Sodium_Core_Ed25519::publickey($keypair);
}
/**
* Calculate an Ed25519 public key from an Ed25519 secret key.
*
* @param string $secretKey Your Ed25519 secret key
* @return string The corresponding Ed25519 public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_publickey_from_secretkey(
#[\SensitiveParameter]
$secretKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_publickey_from_secretkey($secretKey);
}
if (self::use_fallback('crypto_sign_publickey_from_secretkey')) {
return (string) call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey);
}
return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey);
}
/**
* Extract an Ed25519 secret key from an Ed25519 keypair.
*
* @param string $keypair Keypair
* @return string Secret key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_secretkey(
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_secretkey($keypair);
}
if (self::use_fallback('crypto_sign_secretkey')) {
return (string) call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair);
}
return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair);
}
/**
* Calculate the Ed25519 signature of a message and return ONLY the signature.
*
* Algorithm: Ed25519 (EdDSA over Curve25519)
*
* @param string $message Message to be signed
* @param string $secretKey Secret signing key
* @return string Digital signature
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_detached(
$message,
#[\SensitiveParameter]
$secretKey
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_detached($message, $secretKey);
}
if (self::use_fallback('crypto_sign_detached')) {
return (string) call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign_detached($message, $secretKey);
}
return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey);
}
/**
* Verify the Ed25519 signature of a message.
*
* @param string $signature Digital sginature
* @param string $message Message to be verified
* @param string $publicKey Public key
* @return bool TRUE if this signature is good for this public key;
* FALSE otherwise
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_verify_detached($signature, $message, $publicKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($signature, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_verify_detached($signature, $message, $publicKey);
}
if (self::use_fallback('crypto_sign_verify_detached')) {
return (bool) call_user_func(
'\\Sodium\\crypto_sign_verify_detached',
$signature,
$message,
$publicKey
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message, $publicKey);
}
return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey);
}
/**
* Convert an Ed25519 public key to a Curve25519 public key
*
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_ed25519_pk_to_curve25519($pk)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($pk) < self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
if (is_callable('crypto_sign_ed25519_pk_to_curve25519')) {
return (string) sodium_crypto_sign_ed25519_pk_to_curve25519($pk);
}
}
if (self::use_fallback('crypto_sign_ed25519_pk_to_curve25519')) {
return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519', $pk);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::pk_to_curve25519($pk);
}
return ParagonIE_Sodium_Core_Ed25519::pk_to_curve25519($pk);
}
/**
* Convert an Ed25519 secret key to a Curve25519 secret key
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_ed25519_sk_to_curve25519(
#[\SensitiveParameter]
$sk
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) {
throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.');
}
if (self::useNewSodiumAPI()) {
if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) {
return sodium_crypto_sign_ed25519_sk_to_curve25519($sk);
}
}
if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) {
return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk);
}
$h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true);
$h[0] = ParagonIE_Sodium_Core_Util::intToChr(
ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248
);
$h[31] = ParagonIE_Sodium_Core_Util::intToChr(
(ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64
);
return ParagonIE_Sodium_Core_Util::substr($h, 0, 32);
}
/**
* Expand a key and nonce into a keystream of pseudorandom bytes.
*
* @param int $len Number of bytes desired
* @param string $nonce Number to be used Once; must be 24 bytes
* @param string $key XSalsa20 key
* @return string Pseudorandom stream that can be XORed with messages
* to provide encryption (but not authentication; see
* Poly1305 or crypto_auth() for that, which is not
* optional for security)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream(
$len,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_stream($len, $nonce, $key);
}
if (self::use_fallback('crypto_stream')) {
return (string) call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce, $key);
}
return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key);
}
/**
* DANGER! UNAUTHENTICATED ENCRYPTION!
*
* Unless you are following expert advice, do not use this feature.
*
* Algorithm: XSalsa20
*
* This DOES NOT provide ciphertext integrity.
*
* @param string $message Plaintext message
* @param string $nonce Number to be used Once; must be 24 bytes
* @param string $key Encryption key
* @return string Encrypted text which is vulnerable to chosen-
* ciphertext attacks unless you implement some
* other mitigation to the ciphertext (i.e.
* Encrypt then MAC)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream_xor(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_stream_xor($message, $nonce, $key);
}
if (self::use_fallback('crypto_stream_xor')) {
return (string) call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message, $nonce, $key);
}
return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key);
}
/**
* Return a secure random key for use with crypto_stream
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_stream_keygen()
{
return random_bytes(self::CRYPTO_STREAM_KEYBYTES);
}
/**
* Expand a key and nonce into a keystream of pseudorandom bytes.
*
* @param int $len Number of bytes desired
* @param string $nonce Number to be used Once; must be 24 bytes
* @param string $key XChaCha20 key
* @param bool $dontFallback
* @return string Pseudorandom stream that can be XORed with messages
* to provide encryption (but not authentication; see
* Poly1305 or crypto_auth() for that, which is not
* optional for security)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream_xchacha20(
$len,
$nonce,
#[\SensitiveParameter]
$key,
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_STREAM_XCHACHA20_KEYBYTES long.');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_stream_xchacha20($len, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XChaCha20::stream($len, $nonce, $key);
}
return ParagonIE_Sodium_Core_XChaCha20::stream($len, $nonce, $key);
}
/**
* DANGER! UNAUTHENTICATED ENCRYPTION!
*
* Unless you are following expert advice, do not use this feature.
*
* Algorithm: XChaCha20
*
* This DOES NOT provide ciphertext integrity.
*
* @param string $message Plaintext message
* @param string $nonce Number to be used Once; must be 24 bytes
* @param string $key Encryption key
* @return string Encrypted text which is vulnerable to chosen-
* ciphertext attacks unless you implement some
* other mitigation to the ciphertext (i.e.
* Encrypt then MAC)
* @param bool $dontFallback
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream_xchacha20_xor(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key,
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_stream_xchacha20_xor($message, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XChaCha20::streamXorIc($message, $nonce, $key);
}
return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key);
}
/**
* DANGER! UNAUTHENTICATED ENCRYPTION!
*
* Unless you are following expert advice, do not use this feature.
*
* Algorithm: XChaCha20
*
* This DOES NOT provide ciphertext integrity.
*
* @param string $message Plaintext message
* @param string $nonce Number to be used Once; must be 24 bytes
* @param int $counter
* @param string $key Encryption key
* @return string Encrypted text which is vulnerable to chosen-
* ciphertext attacks unless you implement some
* other mitigation to the ciphertext (i.e.
* Encrypt then MAC)
* @param bool $dontFallback
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream_xchacha20_xor_ic(
#[\SensitiveParameter]
$message,
$nonce,
$counter,
#[\SensitiveParameter]
$key,
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($counter, 'int', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.');
}
if (is_callable('sodium_crypto_stream_xchacha20_xor_ic') && !$dontFallback) {
return sodium_crypto_stream_xchacha20_xor_ic($message, $nonce, $counter, $key);
}
$ic = ParagonIE_Sodium_Core_Util::store64_le($counter);
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XChaCha20::streamXorIc($message, $nonce, $key, $ic);
}
return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key, $ic);
}
/**
* Return a secure random key for use with crypto_stream_xchacha20
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_stream_xchacha20_keygen()
{
return random_bytes(self::CRYPTO_STREAM_XCHACHA20_KEYBYTES);
}
/**
* Cache-timing-safe implementation of hex2bin().
*
* @param string $string Hexadecimal string
* @param string $ignore List of characters to ignore; useful for whitespace
* @return string Raw binary string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress TooFewArguments
* @psalm-suppress MixedArgument
*/
public static function hex2bin(
#[\SensitiveParameter]
$string,
$ignore = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($ignore, 'string', 2);
if (self::useNewSodiumAPI()) {
if (is_callable('sodium_hex2bin')) {
return (string) sodium_hex2bin($string, $ignore);
}
}
if (self::use_fallback('hex2bin')) {
return (string) call_user_func('\\Sodium\\hex2bin', $string, $ignore);
}
return ParagonIE_Sodium_Core_Util::hex2bin($string, $ignore);
}
/**
* Increase a string (little endian)
*
* @param string $var
*
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function increment(
#[\SensitiveParameter]
&$var
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1);
if (self::useNewSodiumAPI()) {
sodium_increment($var);
return;
}
if (self::use_fallback('increment')) {
$func = '\\Sodium\\increment';
$func($var);
return;
}
$len = ParagonIE_Sodium_Core_Util::strlen($var);
$c = 1;
$copy = '';
for ($i = 0; $i < $len; ++$i) {
$c += ParagonIE_Sodium_Core_Util::chrToInt(
ParagonIE_Sodium_Core_Util::substr($var, $i, 1)
);
$copy .= ParagonIE_Sodium_Core_Util::intToChr($c);
$c >>= 8;
}
$var = $copy;
}
/**
* @param string $str
* @return bool
*
* @throws SodiumException
*/
public static function is_zero(
#[\SensitiveParameter]
$str
) {
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= ParagonIE_Sodium_Core_Util::chrToInt($str[$i]);
}
return ((($d - 1) >> 31) & 1) === 1;
}
/**
* The equivalent to the libsodium minor version we aim to be compatible
* with (sans pwhash and memzero).
*
* @return int
*/
public static function library_version_major()
{
if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MAJOR_VERSION')) {
return SODIUM_LIBRARY_MAJOR_VERSION;
}
if (self::use_fallback('library_version_major')) {
/** @psalm-suppress UndefinedFunction */
return (int) call_user_func('\\Sodium\\library_version_major');
}
return self::LIBRARY_VERSION_MAJOR;
}
/**
* The equivalent to the libsodium minor version we aim to be compatible
* with (sans pwhash and memzero).
*
* @return int
*/
public static function library_version_minor()
{
if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MINOR_VERSION')) {
return SODIUM_LIBRARY_MINOR_VERSION;
}
if (self::use_fallback('library_version_minor')) {
/** @psalm-suppress UndefinedFunction */
return (int) call_user_func('\\Sodium\\library_version_minor');
}
return self::LIBRARY_VERSION_MINOR;
}
/**
* Compare two strings.
*
* @param string $left
* @param string $right
* @return int
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function memcmp(
#[\SensitiveParameter]
$left,
#[\SensitiveParameter]
$right
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
if (self::useNewSodiumAPI()) {
return sodium_memcmp($left, $right);
}
if (self::use_fallback('memcmp')) {
return (int) call_user_func('\\Sodium\\memcmp', $left, $right);
}
/** @var string $left */
/** @var string $right */
return ParagonIE_Sodium_Core_Util::memcmp($left, $right);
}
/**
* It's actually not possible to zero memory buffers in PHP. You need the
* native library for that.
*
* @param string|null $var
* @param-out string|null $var
*
* @return void
* @throws SodiumException (Unless libsodium is installed)
* @throws TypeError
* @psalm-suppress TooFewArguments
*/
public static function memzero(
#[\SensitiveParameter]
&$var
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1);
if (self::useNewSodiumAPI()) {
/** @psalm-suppress MixedArgument */
sodium_memzero($var);
return;
}
if (self::use_fallback('memzero')) {
$func = '\\Sodium\\memzero';
$func($var);
if ($var === null) {
return;
}
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented in sodium_compat, as it is not possible to securely wipe memory from PHP. ' .
'To fix this error, make sure libsodium is installed and the PHP extension is enabled.'
);
}
/**
* @param string $unpadded
* @param int $blockSize
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function pad(
#[\SensitiveParameter]
$unpadded,
$blockSize,
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($unpadded, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
$unpadded = (string) $unpadded;
$blockSize = (int) $blockSize;
if (self::useNewSodiumAPI() && !$dontFallback) {
return (string) sodium_pad($unpadded, $blockSize);
}
if ($blockSize <= 0) {
throw new SodiumException(
'block size cannot be less than 1'
);
}
$unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded);
$xpadlen = ($blockSize - 1);
if (($blockSize & ($blockSize - 1)) === 0) {
$xpadlen -= $unpadded_len & ($blockSize - 1);
} else {
$xpadlen -= $unpadded_len % $blockSize;
}
$xpadded_len = $unpadded_len + $xpadlen;
$padded = str_repeat("\0", $xpadded_len - 1);
if ($unpadded_len > 0) {
$st = 1;
$i = 0;
$k = $unpadded_len;
for ($j = 0; $j <= $xpadded_len; ++$j) {
$i = (int) $i;
$k = (int) $k;
$st = (int) $st;
if ($j >= $unpadded_len) {
$padded[$j] = "\0";
} else {
$padded[$j] = $unpadded[$j];
}
/** @var int $k */
$k -= $st;
$st = (int) (~(
(
(
($k >> 48)
|
($k >> 32)
|
($k >> 16)
|
$k
) - 1
) >> 16
)
) & 1;
$i += $st;
}
}
$mask = 0;
$tail = $xpadded_len;
for ($i = 0; $i < $blockSize; ++$i) {
# barrier_mask = (unsigned char)
# (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
$barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1);
# tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
$padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr(
(ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask)
|
(0x80 & $barrier_mask)
);
# mask |= barrier_mask;
$mask |= $barrier_mask;
}
return $padded;
}
/**
* @param string $padded
* @param int $blockSize
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function unpad(
#[\SensitiveParameter]
$padded,
$blockSize,
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($padded, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
$padded = (string) $padded;
$blockSize = (int) $blockSize;
if (self::useNewSodiumAPI() && !$dontFallback) {
return (string) sodium_unpad($padded, $blockSize);
}
if ($blockSize <= 0) {
throw new SodiumException('block size cannot be less than 1');
}
$padded_len = ParagonIE_Sodium_Core_Util::strlen($padded);
if ($padded_len < $blockSize) {
throw new SodiumException('invalid padding');
}
# tail = &padded[padded_len - 1U];
$tail = $padded_len - 1;
$acc = 0;
$valid = 0;
$pad_len = 0;
$found = 0;
for ($i = 0; $i < $blockSize; ++$i) {
# c = tail[-i];
$c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]);
# is_barrier =
# (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
$is_barrier = (
(
($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1)
) >> 7
) & 1;
$is_barrier &= ~$found;
$found |= $is_barrier;
# acc |= c;
$acc |= $c;
# pad_len |= i & (1U + ~is_barrier);
$pad_len |= $i & (1 + ~$is_barrier);
# valid |= (unsigned char) is_barrier;
$valid |= ($is_barrier & 0xff);
}
# unpadded_len = padded_len - 1U - pad_len;
$unpadded_len = $padded_len - 1 - $pad_len;
if ($valid !== 1) {
throw new SodiumException('invalid padding');
}
return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len);
}
/**
* Will sodium_compat run fast on the current hardware and PHP configuration?
*
* @return bool
*/
public static function polyfill_is_fast()
{
if (extension_loaded('sodium')) {
return true;
}
if (extension_loaded('libsodium')) {
return true;
}
return PHP_INT_SIZE === 8;
}
/**
* Generate a string of bytes from the kernel's CSPRNG.
* Proudly uses /dev/urandom (if getrandom(2) is not available).
*
* @param int $numBytes
* @return string
* @throws Exception
* @throws TypeError
*/
public static function randombytes_buf($numBytes)
{
/* Type checks: */
if (!is_int($numBytes)) {
if (is_numeric($numBytes)) {
$numBytes = (int) $numBytes;
} else {
throw new TypeError(
'Argument 1 must be an integer, ' . gettype($numBytes) . ' given.'
);
}
}
/** @var positive-int $numBytes */
if (self::use_fallback('randombytes_buf')) {
return (string) call_user_func('\\Sodium\\randombytes_buf', $numBytes);
}
if ($numBytes < 0) {
throw new SodiumException("Number of bytes must be a positive integer");
}
return random_bytes($numBytes);
}
/**
* Generate an integer between 0 and $range (non-inclusive).
*
* @param int $range
* @return int
* @throws Exception
* @throws Error
* @throws TypeError
*/
public static function randombytes_uniform($range)
{
/* Type checks: */
if (!is_int($range)) {
if (is_numeric($range)) {
$range = (int) $range;
} else {
throw new TypeError(
'Argument 1 must be an integer, ' . gettype($range) . ' given.'
);
}
}
if (self::use_fallback('randombytes_uniform')) {
return (int) call_user_func('\\Sodium\\randombytes_uniform', $range);
}
return random_int(0, $range - 1);
}
/**
* Generate a random 16-bit integer.
*
* @return int
* @throws Exception
* @throws Error
* @throws TypeError
*/
public static function randombytes_random16()
{
if (self::use_fallback('randombytes_random16')) {
return (int) call_user_func('\\Sodium\\randombytes_random16');
}
return random_int(0, 65535);
}
/**
* @param string $p
* @param bool $dontFallback
* @return bool
* @throws SodiumException
*/
public static function ristretto255_is_valid_point(
#[\SensitiveParameter]
$p,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_is_valid_point($p);
}
try {
$r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p);
return $r['res'] === 0 &&
ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1;
} catch (SodiumException $ex) {
if ($ex->getMessage() === 'S is not canonical') {
return false;
}
throw $ex;
}
}
/**
* @param string $p
* @param string $q
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_add(
#[\SensitiveParameter]
$p,
#[\SensitiveParameter]
$q,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_add($p, $q);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q);
}
/**
* @param string $p
* @param string $q
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_sub(
#[\SensitiveParameter]
$p,
#[\SensitiveParameter]
$q,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_sub($p, $q);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q);
}
/**
* @param string $r
* @param bool $dontFallback
* @return string
*
* @throws SodiumException
*/
public static function ristretto255_from_hash(
#[\SensitiveParameter]
$r,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_from_hash($r);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r);
}
/**
* @param bool $dontFallback
* @return string
*
* @throws SodiumException
*/
public static function ristretto255_random($dontFallback = false)
{
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_random();
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random();
}
/**
* @param bool $dontFallback
* @return string
*
* @throws SodiumException
*/
public static function ristretto255_scalar_random($dontFallback = false)
{
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_random();
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random();
}
/**
* @param string $s
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_invert(
#[\SensitiveParameter]
$s,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_invert($s);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s);
}
/**
* @param string $s
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_negate(
#[\SensitiveParameter]
$s,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_negate($s);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s);
}
/**
* @param string $s
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_complement(
#[\SensitiveParameter]
$s,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_complement($s);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s);
}
/**
* @param string $x
* @param string $y
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_add(
#[\SensitiveParameter]
$x,
#[\SensitiveParameter]
$y,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_add($x, $y);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y);
}
/**
* @param string $x
* @param string $y
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_sub(
#[\SensitiveParameter]
$x,
#[\SensitiveParameter]
$y,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_sub($x, $y);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y);
}
/**
* @param string $x
* @param string $y
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_mul(
#[\SensitiveParameter]
$x,
#[\SensitiveParameter]
$y,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_mul($x, $y);
}
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y);
}
/**
* @param string $n
* @param string $p
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255(
#[\SensitiveParameter]
$n,
#[\SensitiveParameter]
$p,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_scalarmult_ristretto255($n, $p);
}
return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p);
}
/**
* @param string $n
* @param string $p
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255_base(
#[\SensitiveParameter]
$n,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_scalarmult_ristretto255_base($n);
}
return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n);
}
/**
* @param string $s
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_reduce(
#[\SensitiveParameter]
$s,
$dontFallback = false
) {
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_reduce($s);
}
return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s);
}
/**
* Runtime testing method for 32-bit platforms.
*
* Usage: If runtime_speed_test() returns FALSE, then our 32-bit
* implementation is to slow to use safely without risking timeouts.
* If this happens, install sodium from PECL to get acceptable
* performance.
*
* @param int $iterations Number of multiplications to attempt
* @param int $maxTimeout Milliseconds
* @return bool TRUE if we're fast enough, FALSE is not
* @throws SodiumException
*/
public static function runtime_speed_test($iterations, $maxTimeout)
{
if (self::polyfill_is_fast()) {
return true;
}
/** @var float $end */
$end = 0.0;
/** @var float $start */
$start = microtime(true);
/** @var ParagonIE_Sodium_Core32_Int64 $a */
$a = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16));
for ($i = 0; $i < $iterations; ++$i) {
/** @var ParagonIE_Sodium_Core32_Int64 $b */
$b = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16));
$a->mulInt64($b);
}
/** @var float $end */
$end = microtime(true);
/** @var int $diff */
$diff = (int) ceil(($end - $start) * 1000);
return $diff < $maxTimeout;
}
/**
* Add two numbers (little-endian unsigned), storing the value in the first
* parameter.
*
* This mutates $val.
*
* @param string $val
* @param string $addv
* @return void
* @throws SodiumException
*/
public static function sub(
#[\SensitiveParameter]
&$val,
#[\SensitiveParameter]
$addv
) {
$val_len = ParagonIE_Sodium_Core_Util::strlen($val);
$addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
if ($val_len !== $addv_len) {
throw new SodiumException('values must have the same length');
}
$A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
$B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
$c = 0;
for ($i = 0; $i < $val_len; $i++) {
$c = ($A[$i] - $B[$i] - $c);
$A[$i] = ($c & 0xff);
$c = ($c >> 8) & 1;
}
$val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
}
/**
* This emulates libsodium's version_string() function, except ours is
* prefixed with 'polyfill-'.
*
* @return string
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress UndefinedFunction
*/
public static function version_string()
{
if (self::useNewSodiumAPI()) {
return (string) sodium_version_string();
}
if (self::use_fallback('version_string')) {
return (string) call_user_func('\\Sodium\\version_string');
}
return (string) self::VERSION_STRING;
}
/**
* Should we use the libsodium core function instead?
* This is always a good idea, if it's available. (Unless we're in the
* middle of running our unit test suite.)
*
* If ext/libsodium is available, use it. Return TRUE.
* Otherwise, we have to use the code provided herein. Return FALSE.
*
* @param string $sodium_func_name
*
* @return bool
*/
protected static function use_fallback($sodium_func_name = '')
{
static $res = null;
if ($res === null) {
$res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300;
}
if ($res === false) {
// No libsodium installed
return false;
}
if (self::$disableFallbackForUnitTests) {
// Don't fallback. Use the PHP implementation.
return false;
}
if (!empty($sodium_func_name)) {
return is_callable('\\Sodium\\' . $sodium_func_name);
}
return true;
}
/**
* Libsodium as implemented in PHP 7.2
* and/or ext/sodium (via PECL)
*
* @ref https://wiki.php.net/rfc/libsodium
* @return bool
*/
protected static function useNewSodiumAPI()
{
static $res = null;
if ($res === null) {
$res = PHP_VERSION_ID >= 70000 && extension_loaded('sodium');
}
if (self::$disableFallbackForUnitTests) {
// Don't fallback. Use the PHP implementation.
return false;
}
return (bool) $res;
}
}
[02-Dec-2025 10:42:49 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/File.php:9
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/File.php on line 9
<?php
if (class_exists('ParagonIE_Sodium_File', false)) {
return;
}
/**
* Class ParagonIE_Sodium_File
*/
class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
{
/* PHP's default buffer size is 8192 for fread()/fwrite(). */
const BUFFER_SIZE = 8192;
/**
* Box a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box(), but produces
* the same result.
*
* @param string $inputFile Absolute path to a file on the filesystem
* @param string $outputFile Absolute path to a file on the filesystem
* @param string $nonce Number to be used only once
* @param string $keyPair ECDH secret key and ECDH public key concatenated
*
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box(
$inputFile,
$outputFile,
$nonce,
#[\SensitiveParameter]
$keyPair
) {
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.');
}
/* Input validation: */
if (!is_string($keyPair)) {
throw new TypeError('Argument 4 must be a string, ' . gettype($keyPair) . ' given.');
}
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) {
throw new TypeError('Argument 3 must be CRYPTO_BOX_NONCEBYTES bytes');
}
if (self::strlen($keyPair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new TypeError('Argument 4 must be CRYPTO_BOX_KEYPAIRBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for writing');
}
$res = self::box_encrypt($ifp, $ofp, $size, $nonce, $keyPair);
fclose($ifp);
fclose($ofp);
return $res;
}
/**
* Open a boxed file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box_open(), but produces
* the same result.
*
* Warning: Does not protect against TOCTOU attacks. You should
* just load the file into memory and use crypto_box_open() if
* you are worried about those.
*
* @param string $inputFile
* @param string $outputFile
* @param string $nonce
* @param string $keypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box_open(
$inputFile,
$outputFile,
$nonce,
#[\SensitiveParameter]
$keypair
) {
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.');
}
if (!is_string($keypair)) {
throw new TypeError('Argument 4 must be a string, ' . gettype($keypair) . ' given.');
}
/* Input validation: */
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) {
throw new TypeError('Argument 4 must be CRYPTO_BOX_NONCEBYTES bytes');
}
if (self::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new TypeError('Argument 4 must be CRYPTO_BOX_KEYPAIRBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for writing');
}
$res = self::box_decrypt($ifp, $ofp, $size, $nonce, $keypair);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($nonce);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
} catch (SodiumException $ex) {
if (isset($ephKeypair)) {
unset($ephKeypair);
}
}
return $res;
}
/**
* Seal a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box_seal(), but produces
* the same result.
*
* @param string $inputFile Absolute path to a file on the filesystem
* @param string $outputFile Absolute path to a file on the filesystem
* @param string $publicKey ECDH public key
*
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal(
$inputFile,
$outputFile,
#[\SensitiveParameter]
$publicKey
) {
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.');
}
if (!is_string($publicKey)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.');
}
/* Input validation: */
if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new TypeError('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for writing');
}
/** @var string $ephKeypair */
$ephKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair();
/** @var string $msgKeypair */
$msgKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey(
ParagonIE_Sodium_Compat::crypto_box_secretkey($ephKeypair),
$publicKey
);
/** @var string $ephemeralPK */
$ephemeralPK = ParagonIE_Sodium_Compat::crypto_box_publickey($ephKeypair);
/** @var string $nonce */
$nonce = ParagonIE_Sodium_Compat::crypto_generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var int $firstWrite */
$firstWrite = fwrite(
$ofp,
$ephemeralPK,
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES
);
if (!is_int($firstWrite)) {
fclose($ifp);
fclose($ofp);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
throw new SodiumException('Could not write to output file');
}
if ($firstWrite !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) {
ParagonIE_Sodium_Compat::memzero($ephKeypair);
fclose($ifp);
fclose($ofp);
throw new SodiumException('Error writing public key to output file');
}
$res = self::box_encrypt($ifp, $ofp, $size, $nonce, $msgKeypair);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($nonce);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
} catch (SodiumException $ex) {
/** @psalm-suppress PossiblyUndefinedVariable */
unset($ephKeypair);
}
return $res;
}
/**
* Open a sealed file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box_seal_open(), but produces
* the same result.
*
* Warning: Does not protect against TOCTOU attacks. You should
* just load the file into memory and use crypto_box_seal_open() if
* you are worried about those.
*
* @param string $inputFile
* @param string $outputFile
* @param string $ecdhKeypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal_open(
$inputFile,
$outputFile,
#[\SensitiveParameter]
$ecdhKeypair
) {
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.');
}
if (!is_string($ecdhKeypair)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($ecdhKeypair) . ' given.');
}
/* Input validation: */
if (self::strlen($ecdhKeypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new TypeError('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES bytes');
}
$publicKey = ParagonIE_Sodium_Compat::crypto_box_publickey($ecdhKeypair);
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for writing');
}
$ephemeralPK = fread($ifp, ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES);
if (!is_string($ephemeralPK)) {
throw new SodiumException('Could not read input file');
}
if (self::strlen($ephemeralPK) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) {
fclose($ifp);
fclose($ofp);
throw new SodiumException('Could not read public key from sealed file');
}
$nonce = ParagonIE_Sodium_Compat::crypto_generichash(
$ephemeralPK . $publicKey,
'',
24
);
$msgKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey(
ParagonIE_Sodium_Compat::crypto_box_secretkey($ecdhKeypair),
$ephemeralPK
);
$res = self::box_decrypt($ifp, $ofp, $size, $nonce, $msgKeypair);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($nonce);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
} catch (SodiumException $ex) {
if (isset($ephKeypair)) {
unset($ephKeypair);
}
}
return $res;
}
/**
* Calculate the BLAKE2b hash of a file.
*
* @param string $filePath Absolute path to a file on the filesystem
* @param string|null $key BLAKE2b key
* @param int $outputLength Length of hash output
*
* @return string BLAKE2b hash
* @throws SodiumException
* @throws TypeError
* @psalm-suppress FailedTypeResolution
*/
public static function generichash(
$filePath,
#[\SensitiveParameter]
$key = '',
$outputLength = 32
) {
/* Type checks: */
if (!is_string($filePath)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.');
}
if (!is_string($key)) {
if (is_null($key)) {
$key = '';
} else {
throw new TypeError('Argument 2 must be a string, ' . gettype($key) . ' given.');
}
}
if (!is_int($outputLength)) {
if (!is_numeric($outputLength)) {
throw new TypeError('Argument 3 must be an integer, ' . gettype($outputLength) . ' given.');
}
$outputLength = (int) $outputLength;
}
/* Input validation: */
if (!empty($key)) {
if (self::strlen($key) < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new TypeError('Argument 2 must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes');
}
if (self::strlen($key) > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new TypeError('Argument 2 must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes');
}
}
if ($outputLength < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) {
throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MIN');
}
if ($outputLength > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) {
throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MAX');
}
/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for reading');
}
$ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outputLength);
while ($size > 0) {
$blockSize = $size > 64
? 64
: $size;
$read = fread($fp, $blockSize);
if (!is_string($read)) {
throw new SodiumException('Could not read input file');
}
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $read);
$size -= $blockSize;
}
fclose($fp);
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength);
}
/**
* Encrypt a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_secretbox(), but produces
* the same result.
*
* @param string $inputFile Absolute path to a file on the filesystem
* @param string $outputFile Absolute path to a file on the filesystem
* @param string $nonce Number to be used only once
* @param string $key Encryption key
*
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox(
$inputFile,
$outputFile,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given..');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.');
}
/* Input validation: */
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new TypeError('Argument 3 must be CRYPTO_SECRETBOX_NONCEBYTES bytes');
}
if (!is_string($key)) {
throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.');
}
if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) {
throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_KEYBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for writing');
}
$res = self::secretbox_encrypt($ifp, $ofp, $size, $nonce, $key);
fclose($ifp);
fclose($ofp);
return $res;
}
/**
* Seal a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_secretbox_open(), but produces
* the same result.
*
* Warning: Does not protect against TOCTOU attacks. You should
* just load the file into memory and use crypto_secretbox_open() if
* you are worried about those.
*
* @param string $inputFile
* @param string $outputFile
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_open(
$inputFile,
$outputFile,
$nonce,
#[\SensitiveParameter]
$key
) {
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.');
}
if (!is_string($key)) {
throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.');
}
/* Input validation: */
if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_NONCEBYTES bytes');
}
if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) {
throw new TypeError('Argument 4 must be CRYPTO_SECRETBOXBOX_KEYBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for writing');
}
$res = self::secretbox_decrypt($ifp, $ofp, $size, $nonce, $key);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($key);
} catch (SodiumException $ex) {
/** @psalm-suppress PossiblyUndefinedVariable */
unset($key);
}
return $res;
}
/**
* Sign a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces
* the same result.
*
* @param string $filePath Absolute path to a file on the filesystem
* @param string $secretKey Secret signing key
*
* @return string Ed25519 signature
* @throws SodiumException
* @throws TypeError
*/
public static function sign(
$filePath,
#[\SensitiveParameter]
$secretKey
) {
/* Type checks: */
if (!is_string($filePath)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.');
}
if (!is_string($secretKey)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($secretKey) . ' given.');
}
/* Input validation: */
if (self::strlen($secretKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new TypeError('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES bytes');
}
if (PHP_INT_SIZE === 4) {
return self::sign_core32($filePath, $secretKey);
}
/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var string $az */
$az = hash('sha512', self::substr($secretKey, 0, 32), true);
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($az, 32, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $nonceHash */
$nonceHash = hash_final($hs, true);
/** @var string $pk */
$pk = self::substr($secretKey, 32, 32);
/** @var string $nonce */
$nonce = ParagonIE_Sodium_Core_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
/** @var string $sig */
$sig = ParagonIE_Sodium_Core_Ed25519::ge_p3_tobytes(
ParagonIE_Sodium_Core_Ed25519::ge_scalarmult_base($nonce)
);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($sig, 0, 32));
self::hash_update($hs, self::substr($pk, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hramHash */
$hramHash = hash_final($hs, true);
/** @var string $hram */
$hram = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hramHash);
/** @var string $sigAfter */
$sigAfter = ParagonIE_Sodium_Core_Ed25519::sc_muladd($hram, $az, $nonce);
/** @var string $sig */
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
fclose($fp);
return $sig;
}
/**
* Verify a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but
* produces the same result.
*
* @param string $sig Ed25519 signature
* @param string $filePath Absolute path to a file on the filesystem
* @param string $publicKey Signing public key
*
* @return bool
* @throws SodiumException
* @throws TypeError
* @throws Exception
*/
public static function verify(
$sig,
$filePath,
$publicKey
) {
/* Type checks: */
if (!is_string($sig)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($sig) . ' given.');
}
if (!is_string($filePath)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($filePath) . ' given.');
}
if (!is_string($publicKey)) {
throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.');
}
/* Input validation: */
if (self::strlen($sig) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES) {
throw new TypeError('Argument 1 must be CRYPTO_SIGN_BYTES bytes');
}
if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new TypeError('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES bytes');
}
if (self::strlen($sig) < 64) {
throw new SodiumException('Signature is too short');
}
if (PHP_INT_SIZE === 4) {
return self::verify_core32($sig, $filePath, $publicKey);
}
/* Security checks */
if (
(ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240)
&&
ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))
) {
throw new SodiumException('S < L - Invalid signature');
}
if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) {
throw new SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($publicKey[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
$A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($sig, 0, 32));
self::hash_update($hs, self::substr($publicKey, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hDigest */
$hDigest = hash_final($hs, true);
/** @var string $h */
$h = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
$R = ParagonIE_Sodium_Core_Ed25519::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = ParagonIE_Sodium_Core_Ed25519::ge_tobytes($R);
// Close the file handle
fclose($fp);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $boxKeypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function box_encrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_encrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto32::box_beforenm(
ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair)
)
);
}
return self::secretbox_encrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto::box_beforenm(
ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto::box_publickey($boxKeypair)
)
);
}
/**
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $boxKeypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function box_decrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_decrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto32::box_beforenm(
ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair)
)
);
}
return self::secretbox_decrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto::box_beforenm(
ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto::box_publickey($boxKeypair)
)
);
}
/**
* Encrypt a file
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_encrypt($ifp, $ofp, $mlen, $nonce, $key)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_encrypt_core32($ifp, $ofp, $mlen, $nonce, $key);
}
$plaintext = fread($ifp, 32);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input file');
}
$first32 = self::ftell($ifp);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen0 = $mlen;
if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor(
$block0,
$realNonce,
$subkey
);
$state = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_Util::substr(
$block0,
0,
ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES
)
);
// Pre-write 16 blank bytes for the Poly1305 tag
$start = self::ftell($ofp);
fwrite($ofp, str_repeat("\x00", 16));
/** @var string $c */
$cBlock = ParagonIE_Sodium_Core_Util::substr(
$block0,
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES
);
$state->update($cBlock);
fwrite($ofp, $cBlock);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/*
* Set the cursor to the end of the first half-block. All future bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
fseek($ifp, $first32, SEEK_SET);
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$plaintext = fread($ifp, $blockSize);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input file');
}
$cBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
$plaintext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $cBlock, $blockSize);
$state->update($cBlock);
$mlen -= $blockSize;
$iter += $incr;
}
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$end = self::ftell($ofp);
/*
* Write the Poly1305 authentication tag that provides integrity
* over the ciphertext (encrypt-then-MAC)
*/
fseek($ofp, $start, SEEK_SET);
fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES);
fseek($ofp, $end, SEEK_SET);
unset($state);
return true;
}
/**
* Decrypt a file
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_decrypt($ifp, $ofp, $mlen, $nonce, $key)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_decrypt_core32($ifp, $ofp, $mlen, $nonce, $key);
}
$tag = fread($ifp, 16);
if (!is_string($tag)) {
throw new SodiumException('Could not read input file');
}
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
/* Verify the Poly1305 MAC -before- attempting to decrypt! */
$state = new ParagonIE_Sodium_Core_Poly1305_State(self::substr($block0, 0, 32));
if (!self::onetimeauth_verify($state, $ifp, $tag, $mlen)) {
throw new SodiumException('Invalid MAC');
}
/*
* Set the cursor to the end of the first half-block. All future bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
$first32 = fread($ifp, 32);
if (!is_string($first32)) {
throw new SodiumException('Could not read input file');
}
$first32len = self::strlen($first32);
fwrite(
$ofp,
self::xorStrings(
self::substr($block0, 32, $first32len),
self::substr($first32, 0, $first32len)
)
);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/* Decrypts ciphertext, writes to output file. */
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input file');
}
$pBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
$ciphertext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $pBlock, $blockSize);
$mlen -= $blockSize;
$iter += $incr;
}
return true;
}
/**
* @param ParagonIE_Sodium_Core_Poly1305_State $state
* @param resource $ifp
* @param string $tag
* @param int $mlen
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function onetimeauth_verify(
ParagonIE_Sodium_Core_Poly1305_State $state,
$ifp,
$tag = '',
$mlen = 0
) {
/** @var int $pos */
$pos = self::ftell($ifp);
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input file');
}
$state->update($ciphertext);
$mlen -= $blockSize;
$iter += $incr;
}
$res = ParagonIE_Sodium_Core_Util::verify_16($tag, $state->finish());
fseek($ifp, $pos, SEEK_SET);
return $res;
}
/**
* Update a hash context with the contents of a file, without
* loading the entire file into memory.
*
* @param resource|HashContext $hash
* @param resource $fp
* @param int $size
* @return resource|object Resource on PHP < 7.2, HashContext object on PHP >= 7.2
* @throws SodiumException
* @throws TypeError
* @psalm-suppress PossiblyInvalidArgument
* PHP 7.2 changes from a resource to an object,
* which causes Psalm to complain about an error.
* @psalm-suppress TypeCoercion
* Ditto.
*/
public static function updateHashWithFile($hash, $fp, $size = 0)
{
/* Type checks: */
if (PHP_VERSION_ID < 70200) {
if (!is_resource($hash)) {
throw new TypeError('Argument 1 must be a resource, ' . gettype($hash) . ' given.');
}
} else {
if (!is_object($hash)) {
throw new TypeError('Argument 1 must be an object (PHP 7.2+), ' . gettype($hash) . ' given.');
}
}
if (!is_resource($fp)) {
throw new TypeError('Argument 2 must be a resource, ' . gettype($fp) . ' given.');
}
if (!is_int($size)) {
throw new TypeError('Argument 3 must be an integer, ' . gettype($size) . ' given.');
}
/** @var int $originalPosition */
$originalPosition = self::ftell($fp);
// Move file pointer to beginning of file
fseek($fp, 0, SEEK_SET);
for ($i = 0; $i < $size; $i += self::BUFFER_SIZE) {
/** @var string|bool $message */
$message = fread(
$fp,
($size - $i) > self::BUFFER_SIZE
? $size - $i
: self::BUFFER_SIZE
);
if (!is_string($message)) {
throw new SodiumException('Unexpected error reading from file.');
}
/** @var string $message */
/** @psalm-suppress InvalidArgument */
self::hash_update($hash, $message);
}
// Reset file pointer's position
fseek($fp, $originalPosition, SEEK_SET);
return $hash;
}
/**
* Sign a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces
* the same result. (32-bit)
*
* @param string $filePath Absolute path to a file on the filesystem
* @param string $secretKey Secret signing key
*
* @return string Ed25519 signature
* @throws SodiumException
* @throws TypeError
*/
private static function sign_core32($filePath, $secretKey)
{
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var string $az */
$az = hash('sha512', self::substr($secretKey, 0, 32), true);
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($az, 32, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
$nonceHash = hash_final($hs, true);
$pk = self::substr($secretKey, 32, 32);
$nonce = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
$sig = ParagonIE_Sodium_Core32_Ed25519::ge_p3_tobytes(
ParagonIE_Sodium_Core32_Ed25519::ge_scalarmult_base($nonce)
);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($sig, 0, 32));
self::hash_update($hs, self::substr($pk, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
$hramHash = hash_final($hs, true);
$hram = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hramHash);
$sigAfter = ParagonIE_Sodium_Core32_Ed25519::sc_muladd($hram, $az, $nonce);
/** @var string $sig */
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
fclose($fp);
return $sig;
}
/**
*
* Verify a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but
* produces the same result. (32-bit)
*
* @param string $sig Ed25519 signature
* @param string $filePath Absolute path to a file on the filesystem
* @param string $publicKey Signing public key
*
* @return bool
* @throws SodiumException
* @throws Exception
*/
public static function verify_core32($sig, $filePath, $publicKey)
{
/* Security checks */
if (ParagonIE_Sodium_Core32_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new SodiumException('S < L - Invalid signature');
}
if (ParagonIE_Sodium_Core32_Ed25519::small_order($sig)) {
throw new SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($publicKey[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var int|bool $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file size');
}
/** @var int $size */
/** @var resource|bool $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for reading');
}
/** @var resource $fp */
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
$A = ParagonIE_Sodium_Core32_Ed25519::ge_frombytes_negate_vartime($publicKey);
$hs = hash_init('sha512');
self::hash_update($hs, self::substr($sig, 0, 32));
self::hash_update($hs, self::substr($publicKey, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hDigest */
$hDigest = hash_final($hs, true);
/** @var string $h */
$h = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
$R = ParagonIE_Sodium_Core32_Ed25519::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = ParagonIE_Sodium_Core32_Ed25519::ge_tobytes($R);
// Close the file handle
fclose($fp);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* Encrypt a file (32-bit)
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_encrypt_core32($ifp, $ofp, $mlen, $nonce, $key)
{
$plaintext = fread($ifp, 32);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input file');
}
$first32 = self::ftell($ifp);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen0 = $mlen;
if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
$block0,
$realNonce,
$subkey
);
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_Util::substr(
$block0,
0,
ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES
)
);
// Pre-write 16 blank bytes for the Poly1305 tag
$start = self::ftell($ofp);
fwrite($ofp, str_repeat("\x00", 16));
/** @var string $c */
$cBlock = ParagonIE_Sodium_Core32_Util::substr(
$block0,
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES
);
$state->update($cBlock);
fwrite($ofp, $cBlock);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/*
* Set the cursor to the end of the first half-block. All future bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
fseek($ifp, $first32, SEEK_SET);
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$plaintext = fread($ifp, $blockSize);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input file');
}
$cBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
$plaintext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $cBlock, $blockSize);
$state->update($cBlock);
$mlen -= $blockSize;
$iter += $incr;
}
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$end = self::ftell($ofp);
/*
* Write the Poly1305 authentication tag that provides integrity
* over the ciphertext (encrypt-then-MAC)
*/
fseek($ofp, $start, SEEK_SET);
fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES);
fseek($ofp, $end, SEEK_SET);
unset($state);
return true;
}
/**
* Decrypt a file (32-bit)
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_decrypt_core32($ifp, $ofp, $mlen, $nonce, $key)
{
$tag = fread($ifp, 16);
if (!is_string($tag)) {
throw new SodiumException('Could not read input file');
}
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
/* Verify the Poly1305 MAC -before- attempting to decrypt! */
$state = new ParagonIE_Sodium_Core32_Poly1305_State(self::substr($block0, 0, 32));
if (!self::onetimeauth_verify_core32($state, $ifp, $tag, $mlen)) {
throw new SodiumException('Invalid MAC');
}
/*
* Set the cursor to the end of the first half-block. All future bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
$first32 = fread($ifp, 32);
if (!is_string($first32)) {
throw new SodiumException('Could not read input file');
}
$first32len = self::strlen($first32);
fwrite(
$ofp,
self::xorStrings(
self::substr($block0, 32, $first32len),
self::substr($first32, 0, $first32len)
)
);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/* Decrypts ciphertext, writes to output file. */
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input file');
}
$pBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
$ciphertext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $pBlock, $blockSize);
$mlen -= $blockSize;
$iter += $incr;
}
return true;
}
/**
* One-time message authentication for 32-bit systems
*
* @param ParagonIE_Sodium_Core32_Poly1305_State $state
* @param resource $ifp
* @param string $tag
* @param int $mlen
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function onetimeauth_verify_core32(
ParagonIE_Sodium_Core32_Poly1305_State $state,
$ifp,
$tag = '',
$mlen = 0
) {
/** @var int $pos */
$pos = self::ftell($ifp);
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input file');
}
$state->update($ciphertext);
$mlen -= $blockSize;
}
$res = ParagonIE_Sodium_Core32_Util::verify_16($tag, $state->finish());
fseek($ifp, $pos, SEEK_SET);
return $res;
}
/**
* @param resource $resource
* @return int
* @throws SodiumException
*/
private static function ftell($resource)
{
$return = ftell($resource);
if (!is_int($return)) {
throw new SodiumException('ftell() returned false');
}
return (int) $return;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Crypto32', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Crypto
*
* ATTENTION!
*
* If you are using this library, you should be using
* ParagonIE_Sodium_Compat in your code, not this class.
*/
abstract class ParagonIE_Sodium_Crypto32
{
const aead_chacha20poly1305_KEYBYTES = 32;
const aead_chacha20poly1305_NSECBYTES = 0;
const aead_chacha20poly1305_NPUBBYTES = 8;
const aead_chacha20poly1305_ABYTES = 16;
const aead_chacha20poly1305_IETF_KEYBYTES = 32;
const aead_chacha20poly1305_IETF_NSECBYTES = 0;
const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
const aead_chacha20poly1305_IETF_ABYTES = 16;
const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
const aead_xchacha20poly1305_IETF_ABYTES = 16;
const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
const box_curve25519xsalsa20poly1305_MACBYTES = 16;
const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
const onetimeauth_poly1305_BYTES = 16;
const onetimeauth_poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
const secretbox_xsalsa20poly1305_MACBYTES = 16;
const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
const secretbox_xchacha20poly1305_KEYBYTES = 32;
const secretbox_xchacha20poly1305_NONCEBYTES = 24;
const secretbox_xchacha20poly1305_MACBYTES = 16;
const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
const secretbox_xchacha20poly1305_ZEROBYTES = 32;
const stream_salsa20_KEYBYTES = 32;
/**
* AEAD Decryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_ABYTES;
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$message,
$clen,
self::aead_chacha20poly1305_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen);
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
32,
$nonce,
$key
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return the plaintext
return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
$state->update($ad);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
32,
$nonce,
$key
);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$message,
$len - self::aead_chacha20poly1305_IETF_ABYTES,
self::aead_chacha20poly1305_IETF_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core32_Util::substr(
$message,
0,
$len - self::aead_chacha20poly1305_IETF_ABYTES
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", (0x10 - $clen) & 0xf));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return the plaintext
return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", ((0x10 - $len) & 0xf)));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey);
}
/**
* HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $key
* @return string
* @throws TypeError
*/
public static function auth($message, $key)
{
return ParagonIE_Sodium_Core32_Util::substr(
hash_hmac('sha512', $message, $key, true),
0,
32
);
}
/**
* HMAC-SHA-512-256 validation. Constant-time via hash_equals().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function auth_verify($mac, $message, $key)
{
return ParagonIE_Sodium_Core32_Util::hashEquals(
$mac,
self::auth($message, $key)
);
}
/**
* X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box($plaintext, $nonce, $keypair)
{
return self::secretbox(
$plaintext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
}
/**
* X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal($message, $publicKey)
{
/** @var string $ephemeralKeypair */
$ephemeralKeypair = self::box_keypair();
/** @var string $ephemeralSK */
$ephemeralSK = self::box_secretkey($ephemeralKeypair);
/** @var string $ephemeralPK */
$ephemeralPK = self::box_publickey($ephemeralKeypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair - The combined keypair used in crypto_box() */
$keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
/** @var string $ciphertext Ciphertext + MAC from crypto_box */
$ciphertext = self::box($message, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
ParagonIE_Sodium_Compat::memzero($ephemeralSK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$ephemeralKeypair = null;
$ephemeralSK = null;
$nonce = null;
}
return $ephemeralPK . $ciphertext;
}
/**
* Opens a message encrypted via box_seal().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal_open($message, $keypair)
{
/** @var string $ephemeralPK */
$ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32);
/** @var string $ciphertext (ciphertext + MAC) */
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32);
/** @var string $secretKey */
$secretKey = self::box_secretkey($keypair);
/** @var string $publicKey */
$publicKey = self::box_publickey($keypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair */
$keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
/** @var string $m */
$m = self::box_open($ciphertext, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($secretKey);
ParagonIE_Sodium_Compat::memzero($ephemeralPK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$secretKey = null;
$ephemeralPK = null;
$nonce = null;
}
return $m;
}
/**
* Used by crypto_box() to get the crypto_secretbox() key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_beforenm($sk, $pk)
{
return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20(
str_repeat("\x00", 16),
self::scalarmult($sk, $pk)
);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @return string
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function box_keypair()
{
$sKey = random_bytes(32);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seed_keypair($seed)
{
$sKey = ParagonIE_Sodium_Core32_Util::substr(
hash('sha512', $seed, true),
0,
32
);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
* @throws TypeError
*/
public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey)
{
return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) .
ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_secretkey($keypair)
{
if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) {
throw new RangeException(
'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_publickey($keypair)
{
if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new RangeException(
'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function box_publickey_from_secretkey($sKey)
{
if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
throw new RangeException(
'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
);
}
return self::scalarmult_base($sKey);
}
/**
* Decrypt a message encrypted with box().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_open($ciphertext, $nonce, $keypair)
{
return self::secretbox_open(
$ciphertext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
}
/**
* Calculate a BLAKE2b hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string|null $key
* @param int $outlen
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash($message, $key = '', $outlen = 32)
{
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
/** @var SplFixedArray $k */
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $in */
$in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen);
ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count());
/** @var SplFixedArray $out */
$out = new SplFixedArray($outlen);
$out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
}
/**
* Finalize a BLAKE2b hashing context, returning the hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param int $outlen
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_final($ctx, $outlen = 32)
{
if (!is_string($ctx)) {
throw new TypeError('Context must be a string');
}
$out = new SplFixedArray($outlen);
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $out */
$out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init($key = '', $outputLength = 32)
{
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength);
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @param string $salt
* @param string $personal
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init_salt_personal(
$key = '',
$outputLength = 32,
$salt = '',
$personal = ''
) {
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
if (!empty($salt)) {
$s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt);
} else {
$s = null;
}
if (!empty($salt)) {
$p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal);
} else {
$p = null;
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p);
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
}
/**
* Update a hashing context for BLAKE2b with $message
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param string $message
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_update($ctx, $message)
{
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $in */
$in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count());
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context);
}
/**
* Libsodium's crypto_kx().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $my_sk
* @param string $their_pk
* @param string $client_pk
* @param string $server_pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk)
{
return self::generichash(
self::scalarmult($my_sk, $their_pk) .
$client_pk .
$server_pk
);
}
/**
* ECDH over Curve25519
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult($sKey, $pKey)
{
$q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* ECDH over Curve25519, using the basepoint.
* Used to get a secret key from a public key.
*
* @param string $secret
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult_base($secret)
{
$q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* This throws an Error if a zero public key was passed to the function.
*
* @param string $q
* @return void
* @throws SodiumException
* @throws TypeError
*/
protected static function scalarmult_throw_if_zero($q)
{
$d = 0;
for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
$d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]);
}
/* branch-free variant of === 0 */
if (-(1 & (($d - 1) >> 8))) {
throw new SodiumException('Zero public key is not allowed');
}
}
/**
* XSalsa20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox($plaintext, $nonce, $key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
$block0,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$block0,
self::secretbox_xsalsa20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core32_Util::substr(
$plaintext,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1,
$subkey
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_open($ciphertext, $nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
0,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core32_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core32_Util::xorStrings(
ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt the rest.
$m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core32_Util::substr(
$c,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1,
(string) $subkey
);
}
return $m;
}
/**
* XChaCha20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
$block0,
$nonceLast,
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$block0,
self::secretbox_xchacha20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core32_Util::substr(
$plaintext,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
$nonceLast,
$subkey,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
0,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core32_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
64,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core32_Util::xorStrings(
ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt the rest.
$m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core32_Util::substr(
$c,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
(string) $subkey,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
return $m;
}
/**
* @param string $key
* @return array<int, string> Returns a state and a header.
* @throws Exception
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_init_push($key)
{
# randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
$out = random_bytes(24);
# crypto_core_hchacha20(state->k, out, k, NULL);
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key);
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4)
);
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$state->counterReset();
# memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
return array(
$state->toString(),
$out
);
}
/**
* @param string $key
* @param string $header
* @return string Returns a state.
* @throws Exception
*/
public static function secretstream_xchacha20poly1305_init_pull($key, $header)
{
# crypto_core_hchacha20(state->k, in, k, NULL);
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($header, 0, 16),
$key
);
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core32_Util::substr($header, 16)
);
$state->counterReset();
# memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
# return 0;
return $state->toString();
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
{
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
# crypto_onetimeauth_poly1305_state poly1305_state;
# unsigned char block[64U];
# unsigned char slen[8U];
# unsigned char *c;
# unsigned char *mac;
$msglen = ParagonIE_Sodium_Core32_Util::strlen($msg);
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# if (outlen_p != NULL) {
# *outlen_p = 0U;
# }
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
# memset(block, 0, sizeof block);
# block[0] = tag;
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
# state->nonce, 1U, state->k);
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
$auth->update($block);
# out[0] = block[0];
$out = $block[0];
# c = out + (sizeof tag);
# crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
$cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$msg,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(2)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
$auth->update($cipher);
$out .= $cipher;
unset($cipher);
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$auth->update($slen);
# mac = c + mlen;
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
$mac = $auth->finish();
$out .= $mac;
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
unset($auth);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
# if (outlen_p != NULL) {
# *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
# }
return $out;
}
/**
* @param string $state
* @param string $cipher
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
{
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
$cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher);
# mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
$msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
# memset(block, 0, sizeof block);
# block[0] = in[0];
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
# state->nonce, 1U, state->k);
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$cipher[0] . str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
# tag = block[0];
# block[0] = in[0];
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
$tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]);
$block[0] = $cipher[0];
$auth->update($block);
# c = in + (sizeof tag);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
$auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen));
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
$auth->update($slen);
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
$mac = $auth->finish();
# stored_mac = c + mlen;
# if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
# sodium_memzero(mac, sizeof mac);
# return -1;
# }
$stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16);
if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) {
return false;
}
# crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
$out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(2)
);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
return array($out, $tag);
}
/**
* @param string $state
* @return void
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_rekey(&$state)
{
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
# unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
# crypto_secretstream_xchacha20poly1305_INONCEBYTES];
# size_t i;
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# new_key_and_inonce[i] = state->k[i];
# }
$new_key_and_inonce = $st->getKey();
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
# STATE_INONCE(state)[i];
# }
$new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8);
# crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
# sizeof new_key_and_inonce,
# state->nonce, state->k);
$st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$new_key_and_inonce,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(0)
));
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# state->k[i] = new_key_and_inonce[i];
# }
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# STATE_INONCE(state)[i] =
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
# }
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$st->counterReset();
$state = $st->toString();
}
/**
* Detached Ed25519 signature.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk);
}
/**
* Attached Ed25519 signature. (Returns a signed message.)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk);
}
/**
* Opens a signed message. If valid, returns the message.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signedMessage
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($signedMessage, $pk)
{
return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk);
}
/**
* Verify a detached signature of a given message and public key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function sign_verify_detached($signature, $message, $pk)
{
return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk);
}
}
<?php
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS128L extends ParagonIE_Sodium_Core_AES
{
/**
* @param string $ct
* @param string $tag
* @param string $ad
* @param string $key
* @param string $nonce
* @return string
* @throws SodiumException
*/
public static function decrypt($ct, $tag, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
$ad_blocks = (self::strlen($ad) + 31) >> 5;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 5, 32);
if (self::strlen($ai) < 32) {
$ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT);
}
$state->absorb($ai);
}
$msg = '';
$cn = self::strlen($ct) & 31;
$ct_blocks = self::strlen($ct) >> 5;
for ($i = 0; $i < $ct_blocks; ++$i) {
$msg .= $state->dec(self::substr($ct, $i << 5, 32));
}
if ($cn) {
$start = $ct_blocks << 5;
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
}
$expected_tag = $state->finalize(
self::strlen($ad) << 3,
self::strlen($msg) << 3
);
if (!self::hashEquals($expected_tag, $tag)) {
try {
// The RFC says to erase msg, so we shall try:
ParagonIE_Sodium_Compat::memzero($msg);
} catch (SodiumException $ex) {
// Do nothing if we cannot memzero
}
throw new SodiumException('verification failed');
}
return $msg;
}
/**
* @param string $msg
* @param string $ad
* @param string $key
* @param string $nonce
* @return array
*
* @throws SodiumException
*/
public static function encrypt($msg, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
// ad_blocks = Split(ZeroPad(ad, 256), 256)
// for ai in ad_blocks:
// Absorb(ai)
$ad_len = self::strlen($ad);
$msg_len = self::strlen($msg);
$ad_blocks = ($ad_len + 31) >> 5;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 5, 32);
if (self::strlen($ai) < 32) {
$ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT);
}
$state->absorb($ai);
}
// msg_blocks = Split(ZeroPad(msg, 256), 256)
// for xi in msg_blocks:
// ct = ct || Enc(xi)
$ct = '';
$msg_blocks = ($msg_len + 31) >> 5;
for ($i = 0; $i < $msg_blocks; ++$i) {
$xi = self::substr($msg, $i << 5, 32);
if (self::strlen($xi) < 32) {
$xi = str_pad($xi, 32, "\0", STR_PAD_RIGHT);
}
$ct .= $state->enc($xi);
}
// tag = Finalize(|ad|, |msg|)
// ct = Truncate(ct, |msg|)
$tag = $state->finalize(
$ad_len << 3,
$msg_len << 3
);
// return ct and tag
return array(
self::substr($ct, 0, $msg_len),
$tag
);
}
/**
* @param string $key
* @param string $nonce
* @return ParagonIE_Sodium_Core_AEGIS_State128L
*/
public static function init($key, $nonce)
{
return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_X25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_X25519
*/
abstract class ParagonIE_Sodium_Core_X25519 extends ParagonIE_Sodium_Core_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @param int $b
* @return void
* @psalm-suppress MixedAssignment
*/
public static function fe_cswap(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g,
$b = 0
) {
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
$g0 = (int) $g[0];
$g1 = (int) $g[1];
$g2 = (int) $g[2];
$g3 = (int) $g[3];
$g4 = (int) $g[4];
$g5 = (int) $g[5];
$g6 = (int) $g[6];
$g7 = (int) $g[7];
$g8 = (int) $g[8];
$g9 = (int) $g[9];
$b = -$b;
$x0 = ($f0 ^ $g0) & $b;
$x1 = ($f1 ^ $g1) & $b;
$x2 = ($f2 ^ $g2) & $b;
$x3 = ($f3 ^ $g3) & $b;
$x4 = ($f4 ^ $g4) & $b;
$x5 = ($f5 ^ $g5) & $b;
$x6 = ($f6 ^ $g6) & $b;
$x7 = ($f7 ^ $g7) & $b;
$x8 = ($f8 ^ $g8) & $b;
$x9 = ($f9 ^ $g9) & $b;
$f[0] = $f0 ^ $x0;
$f[1] = $f1 ^ $x1;
$f[2] = $f2 ^ $x2;
$f[3] = $f3 ^ $x3;
$f[4] = $f4 ^ $x4;
$f[5] = $f5 ^ $x5;
$f[6] = $f6 ^ $x6;
$f[7] = $f7 ^ $x7;
$f[8] = $f8 ^ $x8;
$f[9] = $f9 ^ $x9;
$g[0] = $g0 ^ $x0;
$g[1] = $g1 ^ $x1;
$g[2] = $g2 ^ $x2;
$g[3] = $g3 ^ $x3;
$g[4] = $g4 ^ $x4;
$g[5] = $g5 ^ $x5;
$g[6] = $g6 ^ $x6;
$g[7] = $g7 ^ $x7;
$g[8] = $g8 ^ $x8;
$g[9] = $g9 ^ $x9;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_mul121666(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$h = array(
self::mul((int) $f[0], 121666, 17),
self::mul((int) $f[1], 121666, 17),
self::mul((int) $f[2], 121666, 17),
self::mul((int) $f[3], 121666, 17),
self::mul((int) $f[4], 121666, 17),
self::mul((int) $f[5], 121666, 17),
self::mul((int) $f[6], 121666, 17),
self::mul((int) $f[7], 121666, 17),
self::mul((int) $f[8], 121666, 17),
self::mul((int) $f[9], 121666, 17)
);
/** @var int $carry9 */
$carry9 = ($h[9] + (1 << 24)) >> 25;
$h[0] += self::mul($carry9, 19, 5);
$h[9] -= $carry9 << 25;
/** @var int $carry1 */
$carry1 = ($h[1] + (1 << 24)) >> 25;
$h[2] += $carry1;
$h[1] -= $carry1 << 25;
/** @var int $carry3 */
$carry3 = ($h[3] + (1 << 24)) >> 25;
$h[4] += $carry3;
$h[3] -= $carry3 << 25;
/** @var int $carry5 */
$carry5 = ($h[5] + (1 << 24)) >> 25;
$h[6] += $carry5;
$h[5] -= $carry5 << 25;
/** @var int $carry7 */
$carry7 = ($h[7] + (1 << 24)) >> 25;
$h[8] += $carry7;
$h[7] -= $carry7 << 25;
/** @var int $carry0 */
$carry0 = ($h[0] + (1 << 25)) >> 26;
$h[1] += $carry0;
$h[0] -= $carry0 << 26;
/** @var int $carry2 */
$carry2 = ($h[2] + (1 << 25)) >> 26;
$h[3] += $carry2;
$h[2] -= $carry2 << 26;
/** @var int $carry4 */
$carry4 = ($h[4] + (1 << 25)) >> 26;
$h[5] += $carry4;
$h[4] -= $carry4 << 26;
/** @var int $carry6 */
$carry6 = ($h[6] + (1 << 25)) >> 26;
$h[7] += $carry6;
$h[6] -= $carry6 << 26;
/** @var int $carry8 */
$carry8 = ($h[8] + (1 << 25)) >> 26;
$h[9] += $carry8;
$h[8] -= $carry8 << 26;
foreach ($h as $i => $value) {
$h[$i] = (int) $value;
}
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10($n, $p)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
# fe_frombytes(x1,p);
$x1 = self::fe_frombytes($p);
# fe_1(x2);
$x2 = self::fe_1();
# fe_0(z2);
$z2 = self::fe_0();
# fe_copy(x3,x1);
$x3 = self::fe_copy($x1);
# fe_1(z3);
$z3 = self::fe_1();
# swap = 0;
/** @var int $swap */
$swap = 0;
# for (pos = 254;pos >= 0;--pos) {
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
/** @var int $b */
$b = self::chrToInt(
$e[(int) floor($pos / 8)]
) >> ($pos & 7);
# b &= 1;
$b &= 1;
# swap ^= b;
$swap ^= $b;
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# swap = b;
$swap = $b;
# fe_sub(tmp0,x3,z3);
$tmp0 = self::fe_sub($x3, $z3);
# fe_sub(tmp1,x2,z2);
$tmp1 = self::fe_sub($x2, $z2);
# fe_add(x2,x2,z2);
$x2 = self::fe_add($x2, $z2);
# fe_add(z2,x3,z3);
$z2 = self::fe_add($x3, $z3);
# fe_mul(z3,tmp0,x2);
$z3 = self::fe_mul($tmp0, $x2);
# fe_mul(z2,z2,tmp1);
$z2 = self::fe_mul($z2, $tmp1);
# fe_sq(tmp0,tmp1);
$tmp0 = self::fe_sq($tmp1);
# fe_sq(tmp1,x2);
$tmp1 = self::fe_sq($x2);
# fe_add(x3,z3,z2);
$x3 = self::fe_add($z3, $z2);
# fe_sub(z2,z3,z2);
$z2 = self::fe_sub($z3, $z2);
# fe_mul(x2,tmp1,tmp0);
$x2 = self::fe_mul($tmp1, $tmp0);
# fe_sub(tmp1,tmp1,tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
# fe_sq(z2,z2);
$z2 = self::fe_sq($z2);
# fe_mul121666(z3,tmp1);
$z3 = self::fe_mul121666($tmp1);
# fe_sq(x3,x3);
$x3 = self::fe_sq($x3);
# fe_add(tmp0,tmp0,z3);
$tmp0 = self::fe_add($tmp0, $z3);
# fe_mul(z3,x1,z2);
$z3 = self::fe_mul($x1, $z2);
# fe_mul(z2,tmp1,tmp0);
$z2 = self::fe_mul($tmp1, $tmp0);
}
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# fe_invert(z2,z2);
$z2 = self::fe_invert($z2);
# fe_mul(x2,x2,z2);
$x2 = self::fe_mul($x2, $z2);
# fe_tobytes(q,x2);
return self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function edwards_to_montgomery(
ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY,
ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
) {
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base($n)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
$A = self::ge_scalarmult_base($e);
if (
!($A->Y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)
||
!($A->Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)
) {
throw new TypeError('Null points encountered');
}
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) {
return;
}
if (!class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
require_once dirname(__FILE__) . '/Curve25519.php';
}
/**
* Class ParagonIE_Sodium_Core_Ed25519
*/
abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
const SCALAR_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair()
{
$seed = random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(&$pk, &$sk, $seed)
{
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new RangeException('crypto_sign keypair seed must be 32 bytes long');
}
/** @var string $pk */
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function publickey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey($sk)
{
/** @var string $sk */
$sk = hash('sha512', self::substr($sk, 0, 32), true);
$sk[0] = self::intToChr(
self::chrToInt($sk[0]) & 248
);
$sk[31] = self::intToChr(
(self::chrToInt($sk[31]) & 63) | 64
);
return self::sk_to_pk($sk);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519($pk)
{
if (self::small_order($pk)) {
throw new SodiumException('Public key is on a small order');
}
$A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32));
$p1 = self::ge_mul_l($A);
if (!self::fe_isnonzero($p1->X)) {
throw new SodiumException('Unexpected zero result');
}
# fe_1(one_minus_y);
# fe_sub(one_minus_y, one_minus_y, A.Y);
# fe_invert(one_minus_y, one_minus_y);
$one_minux_y = self::fe_invert(
self::fe_sub(
self::fe_1(),
$A->Y
)
);
# fe_1(x);
# fe_add(x, x, A.Y);
# fe_mul(x, x, one_minus_y);
$x = self::fe_mul(
self::fe_add(self::fe_1(), $A->Y),
$one_minux_y
);
# fe_tobytes(curve25519_pk, x);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk($sk)
{
return self::ge_p3_tobytes(
self::ge_scalarmult_base(
self::substr($sk, 0, 32)
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
/** @var string $signature */
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($message, $pk)
{
/** @var string $signature */
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
# crypto_hash_sha512(az, sk, 32);
$az = hash('sha512', self::substr($sk, 0, 32), true);
# az[0] &= 248;
# az[31] &= 63;
# az[31] |= 64;
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, az + 32, 32);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, nonce);
$hs = hash_init('sha512');
hash_update($hs, self::substr($az, 32, 32));
hash_update($hs, $message);
$nonceHash = hash_final($hs, true);
# memmove(sig + 32, sk + 32, 32);
$pk = self::substr($sk, 32, 32);
# sc_reduce(nonce);
# ge_scalarmult_base(&R, nonce);
# ge_p3_tobytes(sig, &R);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
$sig = self::ge_p3_tobytes(
self::ge_scalarmult_base($nonce)
);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, sig, 64);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, hram);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($pk, 0, 32));
hash_update($hs, $message);
$hramHash = hash_final($hs, true);
# sc_reduce(hram);
# sc_muladd(sig + 32, hram, az, nonce);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached($sig, $message, $pk)
{
if (self::strlen($sig) < 64) {
throw new SodiumException('Signature is too short');
}
if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new SodiumException('S < L - Invalid signature');
}
if (self::small_order($sig)) {
throw new SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
$A = self::ge_frombytes_negate_vartime($pk);
/** @var string $hDigest */
$hDigest = hash(
'sha512',
self::substr($sig, 0, 32) .
self::substr($pk, 0, 32) .
$message,
true
);
/** @var string $h */
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
$R = self::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L($S)
{
if (self::strlen($S) < 32) {
throw new SodiumException('Signature must be 32 bytes');
}
$L = array(
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
);
$c = 0;
$n = 1;
$i = 32;
/** @var array<int, int> $L */
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= (
(($x - $L[$i]) >> 8) & $n
);
$n &= (
(($x ^ $L[$i]) - 1) >> 8
);
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order($R)
{
/** @var array<int, array<int, int>> $blocklist */
$blocklist = array(
/* 0 (order 4) */
array(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 1 (order 1) */
array(
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(
0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05
),
/* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(
0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a
),
/* p-1 (order 2) */
array(
0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85
),
/* p (order 4) */
array(
0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa
),
/* p+1 (order 1) */
array(
0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* 2p-1 (order 2) */
array(
0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p (order 4) */
array(
0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p+1 (order 1) */
array(
0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
)
);
/** @var int $countBlocklist */
$countBlocklist = count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j];
}
if ($c === 0) {
return true;
}
}
return false;
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function scalar_complement($s)
{
$t_ = self::L . str_repeat("\x00", 32);
sodium_increment($t_);
$s_ = $s . str_repeat("\x00", 32);
ParagonIE_Sodium_Compat::sub($t_, $s_);
return self::sc_reduce($t_);
}
/**
* @return string
* @throws SodiumException
*/
public static function scalar_random()
{
do {
$r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES);
$r[self::SCALAR_BYTES - 1] = self::intToChr(
self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f
);
} while (
!self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r)
);
return $r;
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function scalar_negate($s)
{
$t_ = self::L . str_repeat("\x00", 32) ;
$s_ = $s . str_repeat("\x00", 32) ;
ParagonIE_Sodium_Compat::sub($t_, $s_);
return self::sc_reduce($t_);
}
/**
* @param string $a
* @param string $b
* @return string
* @throws SodiumException
*/
public static function scalar_add($a, $b)
{
$a_ = $a . str_repeat("\x00", 32);
$b_ = $b . str_repeat("\x00", 32);
ParagonIE_Sodium_Compat::add($a_, $b_);
return self::sc_reduce($a_);
}
/**
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
public static function scalar_sub($x, $y)
{
$yn = self::scalar_negate($y);
return self::scalar_add($x, $yn);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Poly1305', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305
*/
abstract class ParagonIE_Sodium_Core_Poly1305 extends ParagonIE_Sodium_Core_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth($m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
self::substr($key, 0, 32)
);
return $state
->update($m)
->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify($mac, $m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
self::substr($key, 0, 32)
);
$calc = $state
->update($m)
->finish();
return self::verify_16($calc, $mac);
}
}
<?php
/**
* Class ParagonIE_Sodium_Core_SecretStream_State
*/
class ParagonIE_Sodium_Core_SecretStream_State
{
/** @var string $key */
protected $key;
/** @var int $counter */
protected $counter;
/** @var string $nonce */
protected $nonce;
/** @var string $_pad */
protected $_pad;
/**
* ParagonIE_Sodium_Core_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct($key, $nonce = null)
{
$this->key = $key;
$this->counter = 1;
if (is_null($nonce)) {
$nonce = str_repeat("\0", 12);
}
$this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);;
$this->_pad = str_repeat("\0", 4);
}
/**
* @return self
*/
public function counterReset()
{
$this->counter = 1;
$this->_pad = str_repeat("\0", 4);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return string
*/
public function getCounter()
{
return ParagonIE_Sodium_Core_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce()
{
if (!is_string($this->nonce)) {
$this->nonce = str_repeat("\0", 12);
}
if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) {
$this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT);
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce()
{
return $this->getCounter() .
ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8);
}
/**
* @return self
*/
public function incrementCounter()
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey()
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey($newKeyAndNonce)
{
$this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32);
$this->nonce = str_pad(
ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32),
12,
"\0",
STR_PAD_RIGHT
);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce($str)
{
$this->nonce = ParagonIE_Sodium_Core_Util::xorStrings(
$this->getNonce(),
str_pad(
ParagonIE_Sodium_Core_Util::substr($str, 0, 8),
12,
"\0",
STR_PAD_RIGHT
)
);
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString($string)
{
$state = new ParagonIE_Sodium_Core_SecretStream_State(
ParagonIE_Sodium_Core_Util::substr($string, 0, 32)
);
$state->counter = ParagonIE_Sodium_Core_Util::load_4(
ParagonIE_Sodium_Core_Util::substr($string, 32, 4)
);
$state->nonce = ParagonIE_Sodium_Core_Util::substr($string, 36, 12);
$state->_pad = ParagonIE_Sodium_Core_Util::substr($string, 48, 8);
return $state;
}
/**
* @return string
*/
public function toString()
{
return $this->key .
$this->getCounter() .
$this->nonce .
$this->_pad;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
protected static $iv;
/**
* @var array<int, array<int, int>>
*/
protected static $sigma = array(
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4),
array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8),
array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13),
array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9),
array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11),
array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10),
array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5),
array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0),
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3)
);
const BLOCKBYTES = 128;
const OUTBYTES = 64;
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function new64($high, $low)
{
if (PHP_INT_SIZE === 4) {
throw new SodiumException("Error, use 32-bit");
}
$i64 = new SplFixedArray(2);
$i64[0] = $high & 0xffffffff;
$i64[1] = $low & 0xffffffff;
return $i64;
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return SplFixedArray
*/
protected static function to64($num)
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
protected static function add64($x, $y)
{
if (PHP_INT_SIZE === 4) {
throw new SodiumException("Error, use 32-bit");
}
$l = ($x[1] + $y[1]) & 0xffffffff;
return self::new64(
(int) ($x[0] + $y[0] + (
($l < $x[1]) ? 1 : 0
)),
(int) $l
);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @param SplFixedArray $z
* @return SplFixedArray
*/
protected static function add364($x, $y, $z)
{
return self::add64($x, self::add64($y, $z));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
*/
protected static function xor64(SplFixedArray $x, SplFixedArray $y)
{
if (PHP_INT_SIZE === 4) {
throw new SodiumException("Error, use 32-bit");
}
if (!is_numeric($x[0])) {
throw new SodiumException('x[0] is not an integer');
}
if (!is_numeric($x[1])) {
throw new SodiumException('x[1] is not an integer');
}
if (!is_numeric($y[0])) {
throw new SodiumException('y[0] is not an integer');
}
if (!is_numeric($y[1])) {
throw new SodiumException('y[1] is not an integer');
}
return self::new64(
(int) (($x[0] ^ $y[0]) & 0xffffffff),
(int) (($x[1] ^ $y[1]) & 0xffffffff)
);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $c
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function rotr64($x, $c)
{
if (PHP_INT_SIZE === 4) {
throw new SodiumException("Error, use 32-bit");
}
if ($c >= 64) {
$c %= 64;
}
if ($c >= 32) {
/** @var int $tmp */
$tmp = $x[0];
$x[0] = $x[1];
$x[1] = $tmp;
$c -= 32;
}
if ($c === 0) {
return $x;
}
$l0 = 0;
$c = 64 - $c;
/** @var int $c */
if ($c < 32) {
$h0 = ((int) ($x[0]) << $c) | (
(
(int) ($x[1]) & ((1 << $c) - 1)
<<
(32 - $c)
) >> (32 - $c)
);
$l0 = (int) ($x[1]) << $c;
} else {
$h0 = (int) ($x[1]) << ($c - 32);
}
$h1 = 0;
$c1 = 64 - $c;
if ($c1 < 32) {
$h1 = (int) ($x[0]) >> $c1;
$l1 = ((int) ($x[1]) >> $c1) | ((int) ($x[0]) & ((1 << $c1) - 1)) << (32 - $c1);
} else {
$l1 = (int) ($x[0]) >> ($c1 - 32);
}
return self::new64($h0 | $h1, $l0 | $l1);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @return int
* @psalm-suppress MixedOperand
*/
protected static function flatten64($x)
{
return (int) ($x[0] * 4294967296 + $x[1]);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return SplFixedArray
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
protected static function load64(SplFixedArray $x, $i)
{
/** @var int $l */
$l = (int) ($x[$i])
| ((int) ($x[$i+1]) << 8)
| ((int) ($x[$i+2]) << 16)
| ((int) ($x[$i+3]) << 24);
/** @var int $h */
$h = (int) ($x[$i+4])
| ((int) ($x[$i+5]) << 8)
| ((int) ($x[$i+6]) << 16)
| ((int) ($x[$i+7]) << 24);
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param SplFixedArray $u
* @return void
* @psalm-suppress MixedAssignment
*/
protected static function store64(SplFixedArray $x, $i, SplFixedArray $u)
{
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
/*
[0, 1, 2, 3, 4, 5, 6, 7]
... becomes ...
[0, 0, 0, 0, 1, 1, 1, 1]
*/
/** @var int $uIdx */
$uIdx = ((7 - $j) & 4) >> 2;
$x[$i] = ((int) ($u[$uIdx]) & 0xff);
if (++$i > $maxLength) {
return;
}
/** @psalm-suppress MixedOperand */
$u[$uIdx] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
*/
public static function pseudoConstructor()
{
static $called = false;
if ($called) {
return;
}
self::$iv = new SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
protected static function context()
{
$ctx = new SplFixedArray(6);
$ctx[0] = new SplFixedArray(8); // h
$ctx[1] = new SplFixedArray(2); // t
$ctx[2] = new SplFixedArray(2); // f
$ctx[3] = new SplFixedArray(256); // buf
$ctx[4] = 0; // buflen
$ctx[5] = 0; // last_node (uint8_t)
for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
protected static function compress(SplFixedArray $ctx, SplFixedArray $buf)
{
$m = new SplFixedArray(16);
$v = new SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[ 8] = self::$iv[0];
$v[ 9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i], self::xor64($v[$i], $v[$i+8])
);
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v, SplFixedArray $m)
{
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
* @throws SodiumException
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function increment_counter($ctx, $inc)
{
if ($inc < 0) {
throw new SodiumException('Increasing by a negative number makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (self::flatten64($ctx[1][0]) < $inc) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedOperand
*/
public static function update(SplFixedArray $ctx, SplFixedArray $p, $plen)
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedOperand
*/
public static function finish(SplFixedArray $ctx, SplFixedArray $out)
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new SodiumException('Failed to assert that buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
$ctx[3][$i+$ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function init(
$key = null,
$outlen = 64,
$salt = null,
$personal = null
) {
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (count($key) > 64) {
throw new SodiumException('Invalid key size');
}
$klen = count($key);
}
if ($outlen > 64) {
throw new SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen; // digest_length
$p[1] = $klen; // key_length
$p[2] = 1; // fanout
$p[3] = 1; // depth
if ($salt instanceof SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}
$ctx[0][0] = self::xor64(
$ctx[0][0],
self::load64($p, 0)
);
if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i],
self::load64($p, $i << 3)
);
}
}
if ($klen > 0 && $key instanceof SplFixedArray) {
$block = new SplFixedArray(128);
for ($i = 128; $i--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
* @psalm-suppress MixedArgumentTypeCoercion
*/
public static function stringToSplFixedArray($str = '')
{
$values = unpack('C*', $str);
return SplFixedArray::fromArray(array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
* @throws TypeError
*/
public static function SplFixedArrayToString(SplFixedArray $a)
{
/**
* @var array<int, int|string> $arr
*/
$arr = $a->toArray();
$c = $a->count();
array_unshift($arr, str_repeat('C', $c));
return (string) (call_user_func_array('pack', $arr));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
*/
public static function contextToString(SplFixedArray $ctx)
{
$str = '';
/** @var array<int, array<int, int>> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$str .= self::store32_le($ctxA[$i][1]);
$str .= self::store32_le($ctxA[$i][0]);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctxA = $ctx[$i]->toArray();
$str .= self::store32_le($ctxA[0][1]);
$str .= self::store32_le($ctxA[0][0]);
$str .= self::store32_le($ctxA[1][1]);
$str .= self::store32_le($ctxA[1][0]);
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = (int) $ctx[4];
# size_t buflen;
$str .= implode('', array(
self::intToChr($ctx4 & 0xff),
self::intToChr(($ctx4 >> 8) & 0xff),
self::intToChr(($ctx4 >> 16) & 0xff),
self::intToChr(($ctx4 >> 24) & 0xff),
self::intToChr(($ctx4 >> 32) & 0xff),
self::intToChr(($ctx4 >> 40) & 0xff),
self::intToChr(($ctx4 >> 48) & 0xff),
self::intToChr(($ctx4 >> 56) & 0xff)
));
# uint8_t last_node;
return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements, from
* a string (compatible with \Sodium\crypto_generichash_{init, update, final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAssignment
*/
public static function stringToContext($string)
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = SplFixedArray::fromArray(
array(
self::load_4(
self::substr($string, (($i << 3) + 4), 4)
),
self::load_4(
self::substr($string, (($i << 3) + 0), 4)
)
)
);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = SplFixedArray::fromArray(
array(
self::load_4(self::substr($string, 76 + (($i - 1) << 4), 4)),
self::load_4(self::substr($string, 72 + (($i - 1) << 4), 4))
)
);
$ctx[$i][0] = SplFixedArray::fromArray(
array(
self::load_4(self::substr($string, 68 + (($i - 1) << 4), 4)),
self::load_4(self::substr($string, 64 + (($i - 1) << 4), 4))
)
);
}
# uint8_t buf[2 * 128];
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
# uint8_t buf[2 * 128];
$int = 0;
for ($i = 0; $i < 8; ++$i) {
$int |= self::chrToInt($string[352 + $i]) << ($i << 3);
}
$ctx[4] = $int;
return $ctx;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_SipHash', false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/
class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util
{
/**
* @internal You should not use this directly from another application
*
* @param int[] $v
* @return int[]
*
*/
public static function sipRound(array $v)
{
# v0 += v1;
list($v[0], $v[1]) = self::add(
array($v[0], $v[1]),
array($v[2], $v[3])
);
# v1=ROTL(v1,13);
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 13);
# v1 ^= v0;
$v[2] = (int) $v[2] ^ (int) $v[0];
$v[3] = (int) $v[3] ^ (int) $v[1];
# v0=ROTL(v0,32);
list($v[0], $v[1]) = self::rotl_64((int) $v[0], (int) $v[1], 32);
# v2 += v3;
list($v[4], $v[5]) = self::add(
array((int) $v[4], (int) $v[5]),
array((int) $v[6], (int) $v[7])
);
# v3=ROTL(v3,16);
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 16);
# v3 ^= v2;
$v[6] = (int) $v[6] ^ (int) $v[4];
$v[7] = (int) $v[7] ^ (int) $v[5];
# v0 += v3;
list($v[0], $v[1]) = self::add(
array((int) $v[0], (int) $v[1]),
array((int) $v[6], (int) $v[7])
);
# v3=ROTL(v3,21);
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 21);
# v3 ^= v0;
$v[6] = (int) $v[6] ^ (int) $v[0];
$v[7] = (int) $v[7] ^ (int) $v[1];
# v2 += v1;
list($v[4], $v[5]) = self::add(
array((int) $v[4], (int) $v[5]),
array((int) $v[2], (int) $v[3])
);
# v1=ROTL(v1,17);
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 17);
# v1 ^= v2;;
$v[2] = (int) $v[2] ^ (int) $v[4];
$v[3] = (int) $v[3] ^ (int) $v[5];
# v2=ROTL(v2,32)
list($v[4], $v[5]) = self::rotl_64((int) $v[4], (int) $v[5], 32);
return $v;
}
/**
* Add two 32 bit integers representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int[] $a
* @param int[] $b
* @return array<int, mixed>
*/
public static function add(array $a, array $b)
{
/** @var int $x1 */
$x1 = $a[1] + $b[1];
/** @var int $c */
$c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff
/** @var int $x0 */
$x0 = $a[0] + $b[0] + $c;
return array(
$x0 & 0xffffffff,
$x1 & 0xffffffff
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $int0
* @param int $int1
* @param int $c
* @return array<int, mixed>
*/
public static function rotl_64($int0, $int1, $c)
{
$int0 &= 0xffffffff;
$int1 &= 0xffffffff;
$c &= 63;
if ($c === 32) {
return array($int1, $int0);
}
if ($c > 31) {
$tmp = $int1;
$int1 = $int0;
$int0 = $tmp;
$c &= 31;
}
if ($c === 0) {
return array($int0, $int1);
}
return array(
0xffffffff & (
($int0 << $c)
|
($int1 >> (32 - $c))
),
0xffffffff & (
($int1 << $c)
|
($int0 >> (32 - $c))
),
);
}
/**
* Implements Siphash-2-4 using only 32-bit numbers.
*
* When we split an int into two, the higher bits go to the lower index.
* e.g. 0xDEADBEEFAB10C92D becomes [
* 0 => 0xDEADBEEF,
* 1 => 0xAB10C92D
* ].
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sipHash24($in, $key)
{
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(
0x736f6d65, // 0
0x70736575, // 1
0x646f7261, // 2
0x6e646f6d, // 3
0x6c796765, // 4
0x6e657261, // 5
0x74656462, // 6
0x79746573 // 7
);
// v0 => $v[0], $v[1]
// v1 => $v[2], $v[3]
// v2 => $v[4], $v[5]
// v3 => $v[6], $v[7]
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(
self::load_4(self::substr($key, 4, 4)),
self::load_4(self::substr($key, 0, 4)),
self::load_4(self::substr($key, 12, 4)),
self::load_4(self::substr($key, 8, 4))
);
// k0 => $k[0], $k[1]
// k1 => $k[2], $k[3]
# b = ( ( u64 )inlen ) << 56;
$b = array(
$inlen << 24,
0
);
// See docblock for why the 0th index gets the higher bits.
# v3 ^= k1;
$v[6] ^= $k[2];
$v[7] ^= $k[3];
# v2 ^= k0;
$v[4] ^= $k[0];
$v[5] ^= $k[1];
# v1 ^= k1;
$v[2] ^= $k[2];
$v[3] ^= $k[3];
# v0 ^= k0;
$v[0] ^= $k[0];
$v[1] ^= $k[1];
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = array(
self::load_4(self::substr($in, 4, 4)),
self::load_4(self::substr($in, 0, 4))
);
# v3 ^= m;
$v[6] ^= $m[0];
$v[7] ^= $m[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] ^= $m[0];
$v[1] ^= $m[1];
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b[0] |= self::chrToInt($in[6]) << 16;
case 6:
$b[0] |= self::chrToInt($in[5]) << 8;
case 5:
$b[0] |= self::chrToInt($in[4]);
case 4:
$b[1] |= self::chrToInt($in[3]) << 24;
case 3:
$b[1] |= self::chrToInt($in[2]) << 16;
case 2:
$b[1] |= self::chrToInt($in[1]) << 8;
case 1:
$b[1] |= self::chrToInt($in[0]);
case 0:
break;
}
// See docblock for why the 0th index gets the higher bits.
# v3 ^= b;
$v[6] ^= $b[0];
$v[7] ^= $b[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] ^= $b[0];
$v[1] ^= $b[1];
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
# v2 ^= 0xff;
$v[5] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) .
self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]);
}
}
[02-Dec-2025 10:42:50 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_HChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/XChaCha20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/XChaCha20.php on line 10
[02-Dec-2025 10:42:50 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Ed25519" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Ristretto255.php:6
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Ristretto255.php on line 6
[02-Dec-2025 10:42:50 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Salsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/HSalsa20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/HSalsa20.php on line 10
[02-Dec-2025 10:42:51 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Salsa20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Salsa20.php on line 10
[02-Dec-2025 10:42:51 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/ChaCha20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/ChaCha20.php on line 10
[02-Dec-2025 10:42:51 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_AES" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AEGIS256.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AEGIS256.php on line 10
[02-Dec-2025 10:42:51 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AES.php:14
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AES.php on line 14
[02-Dec-2025 10:42:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/X25519.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/X25519.php on line 10
[02-Dec-2025 10:42:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/BLAKE2b.php:12
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/BLAKE2b.php on line 12
[02-Dec-2025 10:42:52 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_H" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Curve25519.php:16
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Curve25519.php on line 16
[02-Dec-2025 10:42:53 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/SipHash.php:12
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/SipHash.php on line 12
[02-Dec-2025 10:42:53 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_AES" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AEGIS128L.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AEGIS128L.php on line 10
[02-Dec-2025 10:42:53 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/HChaCha20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/HChaCha20.php on line 10
[02-Dec-2025 10:42:53 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Poly1305.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Poly1305.php on line 10
[02-Dec-2025 10:42:54 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_H" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Curve25519.php:16
Stack trace:
#0 /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Ed25519.php(7): require_once()
#1 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Curve25519.php on line 16
[02-Dec-2025 10:42:54 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_HSalsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/XSalsa20.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/XSalsa20.php on line 10
<?php
if (class_exists('ParagonIE_Sodium_Core_XSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XSalsa20
*/
abstract class ParagonIE_Sodium_Core_XSalsa20 extends ParagonIE_Sodium_Core_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20($len, $nonce, $key)
{
$ret = self::salsa20(
$len,
self::substr($nonce, 16, 8),
self::hsalsa20($nonce, $key)
);
return $ret;
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::xsalsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
<?php
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS256 extends ParagonIE_Sodium_Core_AES
{
/**
* @param string $ct
* @param string $tag
* @param string $ad
* @param string $key
* @param string $nonce
* @return string
* @throws SodiumException
*/
public static function decrypt($ct, $tag, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
// ad_blocks = Split(ZeroPad(ad, 128), 128)
$ad_blocks = (self::strlen($ad) + 15) >> 4;
// for ai in ad_blocks:
// Absorb(ai)
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 4, 16);
if (self::strlen($ai) < 16) {
$ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT);
}
$state->absorb($ai);
}
$msg = '';
$cn = self::strlen($ct) & 15;
$ct_blocks = self::strlen($ct) >> 4;
// ct_blocks = Split(ZeroPad(ct, 128), 128)
// cn = Tail(ct, |ct| mod 128)
for ($i = 0; $i < $ct_blocks; ++$i) {
$msg .= $state->dec(self::substr($ct, $i << 4, 16));
}
// if cn is not empty:
// msg = msg || DecPartial(cn)
if ($cn) {
$start = $ct_blocks << 4;
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
}
$expected_tag = $state->finalize(
self::strlen($ad) << 3,
self::strlen($msg) << 3
);
if (!self::hashEquals($expected_tag, $tag)) {
try {
// The RFC says to erase msg, so we shall try:
ParagonIE_Sodium_Compat::memzero($msg);
} catch (SodiumException $ex) {
// Do nothing if we cannot memzero
}
throw new SodiumException('verification failed');
}
return $msg;
}
/**
* @param string $msg
* @param string $ad
* @param string $key
* @param string $nonce
* @return array
* @throws SodiumException
*/
public static function encrypt($msg, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
$ad_len = self::strlen($ad);
$msg_len = self::strlen($msg);
$ad_blocks = ($ad_len + 15) >> 4;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 4, 16);
if (self::strlen($ai) < 16) {
$ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT);
}
$state->absorb($ai);
}
$ct = '';
$msg_blocks = ($msg_len + 15) >> 4;
for ($i = 0; $i < $msg_blocks; ++$i) {
$xi = self::substr($msg, $i << 4, 16);
if (self::strlen($xi) < 16) {
$xi = str_pad($xi, 16, "\0", STR_PAD_RIGHT);
}
$ct .= $state->enc($xi);
}
$tag = $state->finalize(
$ad_len << 3,
$msg_len << 3
);
return array(
self::substr($ct, 0, $msg_len),
$tag
);
}
/**
* @param string $key
* @param string $nonce
* @return ParagonIE_Sodium_Core_AEGIS_State256
*/
public static function init($key, $nonce)
{
return ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce);
}
}
[02-Dec-2025 10:42:58 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20_Ctx" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/ChaCha20/IetfCtx.php on line 10
[02-Dec-2025 10:42:58 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/ChaCha20/Ctx.php on line 10
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core_ChaCha20_IetfCtx extends ParagonIE_Sodium_Core_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($iv) !== 12) {
throw new InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.');
}
parent::__construct($key, self::substr($iv, 0, 8), $counter);
if (!empty($counter)) {
$this->container[12] = self::load_4(self::substr($counter, 0, 4));
}
$this->container[13] = self::load_4(self::substr($iv, 0, 4));
$this->container[14] = self::load_4(self::substr($iv, 4, 4));
$this->container[15] = self::load_4(self::substr($iv, 8, 4));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_Ctx
*/
class ParagonIE_Sodium_Core_ChaCha20_Ctx extends ParagonIE_Sodium_Core_Util implements ArrayAccess
{
/**
* @var SplFixedArray internally, <int, int>
*/
protected $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($key) !== 32) {
throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.');
}
$this->container = new SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = 0x61707865;
$this->container[1] = 0x3320646e;
$this->container[2] = 0x79622d32;
$this->container[3] = 0x6b206574;
$this->container[4] = self::load_4(self::substr($key, 0, 4));
$this->container[5] = self::load_4(self::substr($key, 4, 4));
$this->container[6] = self::load_4(self::substr($key, 8, 4));
$this->container[7] = self::load_4(self::substr($key, 12, 4));
$this->container[8] = self::load_4(self::substr($key, 16, 4));
$this->container[9] = self::load_4(self::substr($key, 20, 4));
$this->container[10] = self::load_4(self::substr($key, 24, 4));
$this->container[11] = self::load_4(self::substr($key, 28, 4));
if (empty($counter)) {
$this->container[12] = 0;
$this->container[13] = 0;
} else {
$this->container[12] = self::load_4(self::substr($counter, 0, 4));
$this->container[13] = self::load_4(self::substr($counter, 4, 4));
}
$this->container[14] = self::load_4(self::substr($iv, 0, 4));
$this->container[15] = self::load_4(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int $value
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!is_int($offset)) {
throw new InvalidArgumentException('Expected an integer');
}
if (!is_int($value)) {
throw new InvalidArgumentException('Expected an integer');
}
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
return isset($this->container[$offset])
? $this->container[$offset]
: null;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Util', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core_Util
{
const U32_MAX = 0xFFFFFFFF;
/**
* @param int $integer
* @param int $size (16, 32, 64)
* @return int
*/
public static function abs($integer, $size = 0)
{
/** @var int $realSize */
$realSize = (PHP_INT_SIZE << 3) - 1;
if ($size) {
--$size;
} else {
/** @var int $size */
$size = $realSize;
}
$negative = -(($integer >> $size) & 1);
return (int) (
($integer ^ $negative)
+
(($negative >> $realSize) & 1)
);
}
/**
* @param string $a
* @param string $b
* @return string
* @throws SodiumException
*/
public static function andStrings($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('Argument 1 must be a string');
}
if (!is_string($b)) {
throw new TypeError('Argument 2 must be a string');
}
$len = self::strlen($a);
if (self::strlen($b) !== $len) {
throw new SodiumException('Both strings must be of equal length to combine with bitwise AND');
}
return $a & $b;
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $binaryString (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hex($binaryString)
{
/* Type checks: */
if (!is_string($binaryString)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($binaryString) . ' given.');
}
$hex = '';
$len = self::strlen($binaryString);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = unpack('C', $binaryString[$i]);
/** @var int $c */
$c = $chunk[1] & 0xf;
/** @var int $b */
$b = $chunk[1] >> 4;
$hex .= pack(
'CC',
(87 + $b + ((($b - 10) >> 8) & ~38)),
(87 + $c + ((($c - 10) >> 8) & ~38))
);
}
return $hex;
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks, returning uppercase letters (as per RFC 4648)
*
* @internal You should not use this directly from another application
*
* @param string $bin_string (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hexUpper($bin_string)
{
$hex = '';
$len = self::strlen($bin_string);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = unpack('C', $bin_string[$i]);
/**
* Lower 16 bits
*
* @var int $c
*/
$c = $chunk[1] & 0xf;
/**
* Upper 16 bits
* @var int $b
*/
$b = $chunk[1] >> 4;
/**
* Use pack() and binary operators to turn the two integers
* into hexadecimal characters. We don't use chr() here, because
* it uses a lookup table internally and we want to avoid
* cache-timing side-channels.
*/
$hex .= pack(
'CC',
(55 + $b + ((($b - 10) >> 8) & ~6)),
(55 + $c + ((($c - 10) >> 8) & ~6))
);
}
return $hex;
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param string $chr
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function chrToInt($chr)
{
/* Type checks: */
if (!is_string($chr)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($chr) . ' given.');
}
if (self::strlen($chr) !== 1) {
throw new SodiumException('chrToInt() expects a string that is exactly 1 character long');
}
/** @var array<int, int> $chunk */
$chunk = unpack('C', $chr);
return (int) ($chunk[1]);
}
/**
* Compares two strings.
*
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @param int $len
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function compare($left, $right, $len = null)
{
$leftLen = self::strlen($left);
$rightLen = self::strlen($right);
if ($len === null) {
$len = max($leftLen, $rightLen);
$left = str_pad($left, $len, "\x00", STR_PAD_RIGHT);
$right = str_pad($right, $len, "\x00", STR_PAD_RIGHT);
}
$gt = 0;
$eq = 1;
$i = $len;
while ($i !== 0) {
--$i;
$gt |= ((self::chrToInt($right[$i]) - self::chrToInt($left[$i])) >> 8) & $eq;
$eq &= ((self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1) >> 8;
}
return ($gt + $gt + $eq) - 1;
}
/**
* If a variable does not match a given type, throw a TypeError.
*
* @param mixed $mixedVar
* @param string $type
* @param int $argumentIndex
* @throws TypeError
* @throws SodiumException
* @return void
*/
public static function declareScalarType(&$mixedVar = null, $type = 'void', $argumentIndex = 0)
{
if (func_num_args() === 0) {
/* Tautology, by default */
return;
}
if (func_num_args() === 1) {
throw new TypeError('Declared void, but passed a variable');
}
$realType = strtolower(gettype($mixedVar));
$type = strtolower($type);
switch ($type) {
case 'null':
if ($mixedVar !== null) {
throw new TypeError('Argument ' . $argumentIndex . ' must be null, ' . $realType . ' given.');
}
break;
case 'integer':
case 'int':
$allow = array('int', 'integer');
if (!in_array($type, $allow)) {
throw new TypeError('Argument ' . $argumentIndex . ' must be an integer, ' . $realType . ' given.');
}
$mixedVar = (int) $mixedVar;
break;
case 'boolean':
case 'bool':
$allow = array('bool', 'boolean');
if (!in_array($type, $allow)) {
throw new TypeError('Argument ' . $argumentIndex . ' must be a boolean, ' . $realType . ' given.');
}
$mixedVar = (bool) $mixedVar;
break;
case 'string':
if (!is_string($mixedVar)) {
throw new TypeError('Argument ' . $argumentIndex . ' must be a string, ' . $realType . ' given.');
}
$mixedVar = (string) $mixedVar;
break;
case 'decimal':
case 'double':
case 'float':
$allow = array('decimal', 'double', 'float');
if (!in_array($type, $allow)) {
throw new TypeError('Argument ' . $argumentIndex . ' must be a float, ' . $realType . ' given.');
}
$mixedVar = (float) $mixedVar;
break;
case 'object':
if (!is_object($mixedVar)) {
throw new TypeError('Argument ' . $argumentIndex . ' must be an object, ' . $realType . ' given.');
}
break;
case 'array':
if (!is_array($mixedVar)) {
if (is_object($mixedVar)) {
if ($mixedVar instanceof ArrayAccess) {
return;
}
}
throw new TypeError('Argument ' . $argumentIndex . ' must be an array, ' . $realType . ' given.');
}
break;
default:
throw new SodiumException('Unknown type (' . $realType .') does not match expect type (' . $type . ')');
}
}
/**
* Evaluate whether or not two strings are equal (in constant-time)
*
* @param string $left
* @param string $right
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function hashEquals($left, $right)
{
/* Type checks: */
if (!is_string($left)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($left) . ' given.');
}
if (!is_string($right)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($right) . ' given.');
}
if (is_callable('hash_equals')) {
return hash_equals($left, $right);
}
$d = 0;
/** @var int $len */
$len = self::strlen($left);
if ($len !== self::strlen($right)) {
return false;
}
for ($i = 0; $i < $len; ++$i) {
$d |= self::chrToInt($left[$i]) ^ self::chrToInt($right[$i]);
}
if ($d !== 0) {
return false;
}
return $left === $right;
}
/**
* Catch hash_update() failures and throw instead of silently proceeding
*
* @param HashContext|resource &$hs
* @param string $data
* @return void
* @throws SodiumException
* @psalm-suppress PossiblyInvalidArgument
*/
protected static function hash_update(&$hs, $data)
{
if (!hash_update($hs, $data)) {
throw new SodiumException('hash_update() failed');
}
}
/**
* Convert a hexadecimal string into a binary string without cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $hexString
* @param string $ignore
* @param bool $strictPadding
* @return string (raw binary)
* @throws RangeException
* @throws TypeError
*/
public static function hex2bin($hexString, $ignore = '', $strictPadding = false)
{
/* Type checks: */
if (!is_string($hexString)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.');
}
if (!is_string($ignore)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($hexString) . ' given.');
}
$hex_pos = 0;
$bin = '';
$c_acc = 0;
$hex_len = self::strlen($hexString);
$state = 0;
if (($hex_len & 1) !== 0) {
if ($strictPadding) {
throw new RangeException(
'Expected an even number of hexadecimal characters'
);
} else {
$hexString = '0' . $hexString;
++$hex_len;
}
}
$chunk = unpack('C*', $hexString);
while ($hex_pos < $hex_len) {
++$hex_pos;
/** @var int $c */
$c = $chunk[$hex_pos];
$c_num = $c ^ 48;
$c_num0 = ($c_num - 10) >> 8;
$c_alpha = ($c & ~32) - 55;
$c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
if (($c_num0 | $c_alpha0) === 0) {
if ($ignore && $state === 0 && strpos($ignore, self::intToChr($c)) !== false) {
continue;
}
throw new RangeException(
'hex2bin() only expects hexadecimal characters'
);
}
$c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
if ($state === 0) {
$c_acc = $c_val * 16;
} else {
$bin .= pack('C', $c_acc | $c_val);
}
$state ^= 1;
}
return $bin;
}
/**
* Turn an array of integers into a string
*
* @internal You should not use this directly from another application
*
* @param array<int, int> $ints
* @return string
*/
public static function intArrayToString(array $ints)
{
$args = $ints;
foreach ($args as $i => $v) {
$args[$i] = (int) ($v & 0xff);
}
array_unshift($args, str_repeat('C', count($ints)));
return (string) (call_user_func_array('pack', $args));
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function intToChr($int)
{
return pack('C', $int);
}
/**
* Load a 3 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_3($string)
{
/* Type checks: */
if (!is_string($string)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 3) {
throw new RangeException(
'String must be 3 bytes or more; ' . self::strlen($string) . ' given.'
);
}
/** @var array<int, int> $unpacked */
$unpacked = unpack('V', $string . "\0");
return (int) ($unpacked[1] & 0xffffff);
}
/**
* Load a 4 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_4($string)
{
/* Type checks: */
if (!is_string($string)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 4) {
throw new RangeException(
'String must be 4 bytes or more; ' . self::strlen($string) . ' given.'
);
}
/** @var array<int, int> $unpacked */
$unpacked = unpack('V', $string);
return (int) $unpacked[1];
}
/**
* Load a 8 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function load64_le($string)
{
/* Type checks: */
if (!is_string($string)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 4) {
throw new RangeException(
'String must be 4 bytes or more; ' . self::strlen($string) . ' given.'
);
}
if (PHP_VERSION_ID >= 50603 && PHP_INT_SIZE === 8) {
/** @var array<int, int> $unpacked */
$unpacked = unpack('P', $string);
return (int) $unpacked[1];
}
/** @var int $result */
$result = (self::chrToInt($string[0]) & 0xff);
$result |= (self::chrToInt($string[1]) & 0xff) << 8;
$result |= (self::chrToInt($string[2]) & 0xff) << 16;
$result |= (self::chrToInt($string[3]) & 0xff) << 24;
$result |= (self::chrToInt($string[4]) & 0xff) << 32;
$result |= (self::chrToInt($string[5]) & 0xff) << 40;
$result |= (self::chrToInt($string[6]) & 0xff) << 48;
$result |= (self::chrToInt($string[7]) & 0xff) << 56;
return (int) $result;
}
/**
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function memcmp($left, $right)
{
if (self::hashEquals($left, $right)) {
return 0;
}
return -1;
}
/**
* Multiply two integers in constant-time
*
* Micro-architecture timing side-channels caused by how your CPU
* implements multiplication are best prevented by never using the
* multiplication operators and ensuring that our code always takes
* the same number of operations to complete, regardless of the values
* of $a and $b.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $size Limits the number of operations (useful for small,
* constant operands)
* @return int
*/
public static function mul($a, $b, $size = 0)
{
if (ParagonIE_Sodium_Compat::$fastMult) {
return (int) ($a * $b);
}
static $defaultSize = null;
/** @var int $defaultSize */
if (!$defaultSize) {
/** @var int $defaultSize */
$defaultSize = (PHP_INT_SIZE << 3) - 1;
}
if ($size < 1) {
/** @var int $size */
$size = $defaultSize;
}
/** @var int $size */
$c = 0;
/**
* Mask is either -1 or 0.
*
* -1 in binary looks like 0x1111 ... 1111
* 0 in binary looks like 0x0000 ... 0000
*
* @var int
*/
$mask = -(($b >> ((int) $defaultSize)) & 1);
/**
* Ensure $b is a positive integer, without creating
* a branching side-channel
*
* @var int $b
*/
$b = ($b & ~$mask) | ($mask & -$b);
/**
* Unless $size is provided:
*
* This loop always runs 32 times when PHP_INT_SIZE is 4.
* This loop always runs 64 times when PHP_INT_SIZE is 8.
*/
for ($i = $size; $i >= 0; --$i) {
$c += (int) ($a & -($b & 1));
$a <<= 1;
$b >>= 1;
}
$c = (int) @($c & -1);
/**
* If $b was negative, we then apply the same value to $c here.
* It doesn't matter much if $a was negative; the $c += above would
* have produced a negative integer to begin with. But a negative $b
* makes $b >>= 1 never return 0, so we would end up with incorrect
* results.
*
* The end result is what we'd expect from integer multiplication.
*/
return (int) (($c & ~$mask) | ($mask & -$c));
}
/**
* Convert any arbitrary numbers into two 32-bit integers that represent
* a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int|float $num
* @return array<int, int>
*/
public static function numericTo64BitInteger($num)
{
$high = 0;
/** @var int $low */
if (PHP_INT_SIZE === 4) {
$low = (int) $num;
} else {
$low = $num & 0xffffffff;
}
if ((+(abs($num))) >= 1) {
if ($num > 0) {
/** @var int $high */
$high = min((+(floor($num/4294967296))), 4294967295);
} else {
/** @var int $high */
$high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296))));
}
}
return array((int) $high, (int) $low);
}
/**
* Store a 24-bit integer into a string, treating it as big-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store_3($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = pack('N', $int);
return self::substr($packed, 1, 3);
}
/**
* Store a 32-bit integer into a string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store32_le($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = pack('V', $int);
return $packed;
}
/**
* Store a 32-bit integer into a string, treating it as big-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store_4($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = pack('N', $int);
return $packed;
}
/**
* Stores a 64-bit integer as an string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store64_le($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
}
}
if (PHP_INT_SIZE === 8) {
if (PHP_VERSION_ID >= 50603) {
/** @var string $packed */
$packed = pack('P', $int);
return $packed;
}
return self::intToChr($int & 0xff) .
self::intToChr(($int >> 8) & 0xff) .
self::intToChr(($int >> 16) & 0xff) .
self::intToChr(($int >> 24) & 0xff) .
self::intToChr(($int >> 32) & 0xff) .
self::intToChr(($int >> 40) & 0xff) .
self::intToChr(($int >> 48) & 0xff) .
self::intToChr(($int >> 56) & 0xff);
}
if ($int > PHP_INT_MAX) {
list($hiB, $int) = self::numericTo64BitInteger($int);
} else {
$hiB = 0;
}
return
self::intToChr(($int ) & 0xff) .
self::intToChr(($int >> 8) & 0xff) .
self::intToChr(($int >> 16) & 0xff) .
self::intToChr(($int >> 24) & 0xff) .
self::intToChr($hiB & 0xff) .
self::intToChr(($hiB >> 8) & 0xff) .
self::intToChr(($hiB >> 16) & 0xff) .
self::intToChr(($hiB >> 24) & 0xff);
}
/**
* Safe string length
*
* @internal You should not use this directly from another application
*
* @ref mbstring.func_overload
*
* @param string $str
* @return int
* @throws TypeError
*/
public static function strlen($str)
{
/* Type checks: */
if (!is_string($str)) {
throw new TypeError('String expected');
}
return (int) (
self::isMbStringOverride()
? mb_strlen($str, '8bit')
: strlen($str)
);
}
/**
* Turn a string into an array of integers
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return array<int, int>
* @throws TypeError
*/
public static function stringToIntArray($string)
{
if (!is_string($string)) {
throw new TypeError('String expected');
}
/**
* @var array<int, int>
*/
$values = array_values(
unpack('C*', $string)
);
return $values;
}
/**
* Safe substring
*
* @internal You should not use this directly from another application
*
* @ref mbstring.func_overload
*
* @param string $str
* @param int $start
* @param int $length
* @return string
* @throws TypeError
*/
public static function substr($str, $start = 0, $length = null)
{
/* Type checks: */
if (!is_string($str)) {
throw new TypeError('String expected');
}
if ($length === 0) {
return '';
}
if (self::isMbStringOverride()) {
if (PHP_VERSION_ID < 50400 && $length === null) {
$length = self::strlen($str);
}
$sub = (string) mb_substr($str, $start, $length, '8bit');
} elseif ($length === null) {
$sub = (string) substr($str, $start);
} else {
$sub = (string) substr($str, $start, $length);
}
if ($sub !== '') {
return $sub;
}
return '';
}
/**
* Compare a 16-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_16($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('String expected');
}
if (!is_string($b)) {
throw new TypeError('String expected');
}
return self::hashEquals(
self::substr($a, 0, 16),
self::substr($b, 0, 16)
);
}
/**
* Compare a 32-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_32($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('String expected');
}
if (!is_string($b)) {
throw new TypeError('String expected');
}
return self::hashEquals(
self::substr($a, 0, 32),
self::substr($b, 0, 32)
);
}
/**
* Calculate $a ^ $b for two strings.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return string
* @throws TypeError
*/
public static function xorStrings($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('Argument 1 must be a string');
}
if (!is_string($b)) {
throw new TypeError('Argument 2 must be a string');
}
return (string) ($a ^ $b);
}
/**
* Returns whether or not mbstring.func_overload is in effect.
*
* @internal You should not use this directly from another application
*
* Note: MB_OVERLOAD_STRING === 2, but we don't reference the constant
* (for nuisance-free PHP 8 support)
*
* @return bool
*/
protected static function isMbStringOverride()
{
static $mbstring = null;
if ($mbstring === null) {
if (!defined('MB_OVERLOAD_STRING')) {
$mbstring = false;
return $mbstring;
}
$mbstring = extension_loaded('mbstring')
&& defined('MB_OVERLOAD_STRING')
&&
((int) (ini_get('mbstring.func_overload')) & 2);
// MB_OVERLOAD_STRING === 2
}
/** @var bool $mbstring */
return $mbstring;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Salsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Salsa20
*/
abstract class ParagonIE_Sodium_Core_Salsa20 extends ParagonIE_Sodium_Core_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function core_salsa20($in, $k, $c = null)
{
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$j0 = $x0 = 0x61707865;
$j5 = $x5 = 0x3320646e;
$j10 = $x10 = 0x79622d32;
$j15 = $x15 = 0x6b206574;
} else {
$j0 = $x0 = self::load_4(self::substr($c, 0, 4));
$j5 = $x5 = self::load_4(self::substr($c, 4, 4));
$j10 = $x10 = self::load_4(self::substr($c, 8, 4));
$j15 = $x15 = self::load_4(self::substr($c, 12, 4));
}
$j1 = $x1 = self::load_4(self::substr($k, 0, 4));
$j2 = $x2 = self::load_4(self::substr($k, 4, 4));
$j3 = $x3 = self::load_4(self::substr($k, 8, 4));
$j4 = $x4 = self::load_4(self::substr($k, 12, 4));
$j6 = $x6 = self::load_4(self::substr($in, 0, 4));
$j7 = $x7 = self::load_4(self::substr($in, 4, 4));
$j8 = $x8 = self::load_4(self::substr($in, 8, 4));
$j9 = $x9 = self::load_4(self::substr($in, 12, 4));
$j11 = $x11 = self::load_4(self::substr($k, 16, 4));
$j12 = $x12 = self::load_4(self::substr($k, 20, 4));
$j13 = $x13 = self::load_4(self::substr($k, 24, 4));
$j14 = $x14 = self::load_4(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
$x0 += $j0;
$x1 += $j1;
$x2 += $j2;
$x3 += $j3;
$x4 += $j4;
$x5 += $j5;
$x6 += $j6;
$x7 += $j7;
$x8 += $j8;
$x9 += $j9;
$x10 += $j10;
$x11 += $j11;
$x12 += $j12;
$x13 += $j13;
$x14 += $j14;
$x15 += $j15;
return self::store32_le($x0) .
self::store32_le($x1) .
self::store32_le($x2) .
self::store32_le($x3) .
self::store32_le($x4) .
self::store32_le($x5) .
self::store32_le($x6) .
self::store32_le($x7) .
self::store32_le($x8) .
self::store32_le($x9) .
self::store32_le($x10) .
self::store32_le($x11) .
self::store32_le($x12) .
self::store32_le($x13) .
self::store32_le($x14) .
self::store32_le($x15);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20($len, $nonce, $key)
{
if (self::strlen($key) !== 32) {
throw new RangeException('Key must be 32 bytes long');
}
$kcopy = '' . $key;
$in = self::substr($nonce, 0, 8) . str_repeat("\0", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy, null);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(
self::core_salsa20($in, $kcopy, null),
0,
$len
);
}
try {
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic($m, $n, $ic, $k)
{
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= ParagonIE_Sodium_Core_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, 64),
self::substr($block, 0, 64)
);
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, $mlen),
self::substr($block, 0, $mlen)
);
}
try {
ParagonIE_Sodium_Compat::memzero($block);
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::salsa20(
self::strlen($message),
$nonce,
$key
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $u
* @param int $c
* @return int
*/
public static function rotate($u, $c)
{
$u &= 0xffffffff;
$c %= 32;
return (int) (0xffffffff & (
($u << $c)
|
($u >> (32 - $c))
)
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_AES', false)) {
return;
}
/**
* Bitsliced implementation of the AES block cipher.
*
* Based on the implementation provided by BearSSL.
*
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES extends ParagonIE_Sodium_Core_Util
{
/**
* @var int[] AES round constants
*/
private static $Rcon = array(
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
);
/**
* Mutates the values of $q!
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function sbox(ParagonIE_Sodium_Core_AES_Block $q)
{
/**
* @var int $x0
* @var int $x1
* @var int $x2
* @var int $x3
* @var int $x4
* @var int $x5
* @var int $x6
* @var int $x7
*/
$x0 = $q[7] & self::U32_MAX;
$x1 = $q[6] & self::U32_MAX;
$x2 = $q[5] & self::U32_MAX;
$x3 = $q[4] & self::U32_MAX;
$x4 = $q[3] & self::U32_MAX;
$x5 = $q[2] & self::U32_MAX;
$x6 = $q[1] & self::U32_MAX;
$x7 = $q[0] & self::U32_MAX;
$y14 = $x3 ^ $x5;
$y13 = $x0 ^ $x6;
$y9 = $x0 ^ $x3;
$y8 = $x0 ^ $x5;
$t0 = $x1 ^ $x2;
$y1 = $t0 ^ $x7;
$y4 = $y1 ^ $x3;
$y12 = $y13 ^ $y14;
$y2 = $y1 ^ $x0;
$y5 = $y1 ^ $x6;
$y3 = $y5 ^ $y8;
$t1 = $x4 ^ $y12;
$y15 = $t1 ^ $x5;
$y20 = $t1 ^ $x1;
$y6 = $y15 ^ $x7;
$y10 = $y15 ^ $t0;
$y11 = $y20 ^ $y9;
$y7 = $x7 ^ $y11;
$y17 = $y10 ^ $y11;
$y19 = $y10 ^ $y8;
$y16 = $t0 ^ $y11;
$y21 = $y13 ^ $y16;
$y18 = $x0 ^ $y16;
/*
* Non-linear section.
*/
$t2 = $y12 & $y15;
$t3 = $y3 & $y6;
$t4 = $t3 ^ $t2;
$t5 = $y4 & $x7;
$t6 = $t5 ^ $t2;
$t7 = $y13 & $y16;
$t8 = $y5 & $y1;
$t9 = $t8 ^ $t7;
$t10 = $y2 & $y7;
$t11 = $t10 ^ $t7;
$t12 = $y9 & $y11;
$t13 = $y14 & $y17;
$t14 = $t13 ^ $t12;
$t15 = $y8 & $y10;
$t16 = $t15 ^ $t12;
$t17 = $t4 ^ $t14;
$t18 = $t6 ^ $t16;
$t19 = $t9 ^ $t14;
$t20 = $t11 ^ $t16;
$t21 = $t17 ^ $y20;
$t22 = $t18 ^ $y19;
$t23 = $t19 ^ $y21;
$t24 = $t20 ^ $y18;
$t25 = $t21 ^ $t22;
$t26 = $t21 & $t23;
$t27 = $t24 ^ $t26;
$t28 = $t25 & $t27;
$t29 = $t28 ^ $t22;
$t30 = $t23 ^ $t24;
$t31 = $t22 ^ $t26;
$t32 = $t31 & $t30;
$t33 = $t32 ^ $t24;
$t34 = $t23 ^ $t33;
$t35 = $t27 ^ $t33;
$t36 = $t24 & $t35;
$t37 = $t36 ^ $t34;
$t38 = $t27 ^ $t36;
$t39 = $t29 & $t38;
$t40 = $t25 ^ $t39;
$t41 = $t40 ^ $t37;
$t42 = $t29 ^ $t33;
$t43 = $t29 ^ $t40;
$t44 = $t33 ^ $t37;
$t45 = $t42 ^ $t41;
$z0 = $t44 & $y15;
$z1 = $t37 & $y6;
$z2 = $t33 & $x7;
$z3 = $t43 & $y16;
$z4 = $t40 & $y1;
$z5 = $t29 & $y7;
$z6 = $t42 & $y11;
$z7 = $t45 & $y17;
$z8 = $t41 & $y10;
$z9 = $t44 & $y12;
$z10 = $t37 & $y3;
$z11 = $t33 & $y4;
$z12 = $t43 & $y13;
$z13 = $t40 & $y5;
$z14 = $t29 & $y2;
$z15 = $t42 & $y9;
$z16 = $t45 & $y14;
$z17 = $t41 & $y8;
/*
* Bottom linear transformation.
*/
$t46 = $z15 ^ $z16;
$t47 = $z10 ^ $z11;
$t48 = $z5 ^ $z13;
$t49 = $z9 ^ $z10;
$t50 = $z2 ^ $z12;
$t51 = $z2 ^ $z5;
$t52 = $z7 ^ $z8;
$t53 = $z0 ^ $z3;
$t54 = $z6 ^ $z7;
$t55 = $z16 ^ $z17;
$t56 = $z12 ^ $t48;
$t57 = $t50 ^ $t53;
$t58 = $z4 ^ $t46;
$t59 = $z3 ^ $t54;
$t60 = $t46 ^ $t57;
$t61 = $z14 ^ $t57;
$t62 = $t52 ^ $t58;
$t63 = $t49 ^ $t58;
$t64 = $z4 ^ $t59;
$t65 = $t61 ^ $t62;
$t66 = $z1 ^ $t63;
$s0 = $t59 ^ $t63;
$s6 = $t56 ^ ~$t62;
$s7 = $t48 ^ ~$t60;
$t67 = $t64 ^ $t65;
$s3 = $t53 ^ $t66;
$s4 = $t51 ^ $t66;
$s5 = $t47 ^ $t65;
$s1 = $t64 ^ ~$s3;
$s2 = $t55 ^ ~$t67;
$q[7] = $s0 & self::U32_MAX;
$q[6] = $s1 & self::U32_MAX;
$q[5] = $s2 & self::U32_MAX;
$q[4] = $s3 & self::U32_MAX;
$q[3] = $s4 & self::U32_MAX;
$q[2] = $s5 & self::U32_MAX;
$q[1] = $s6 & self::U32_MAX;
$q[0] = $s7 & self::U32_MAX;
}
/**
* Mutates the values of $q!
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function invSbox(ParagonIE_Sodium_Core_AES_Block $q)
{
self::processInversion($q);
self::sbox($q);
self::processInversion($q);
}
/**
* This is some boilerplate code needed to invert an S-box. Rather than repeat the code
* twice, I moved it to a protected method.
*
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
protected static function processInversion(ParagonIE_Sodium_Core_AES_Block $q)
{
$q0 = (~$q[0]) & self::U32_MAX;
$q1 = (~$q[1]) & self::U32_MAX;
$q2 = $q[2] & self::U32_MAX;
$q3 = $q[3] & self::U32_MAX;
$q4 = $q[4] & self::U32_MAX;
$q5 = (~$q[5]) & self::U32_MAX;
$q6 = (~$q[6]) & self::U32_MAX;
$q7 = $q[7] & self::U32_MAX;
$q[7] = ($q1 ^ $q4 ^ $q6) & self::U32_MAX;
$q[6] = ($q0 ^ $q3 ^ $q5) & self::U32_MAX;
$q[5] = ($q7 ^ $q2 ^ $q4) & self::U32_MAX;
$q[4] = ($q6 ^ $q1 ^ $q3) & self::U32_MAX;
$q[3] = ($q5 ^ $q0 ^ $q2) & self::U32_MAX;
$q[2] = ($q4 ^ $q7 ^ $q1) & self::U32_MAX;
$q[1] = ($q3 ^ $q6 ^ $q0) & self::U32_MAX;
$q[0] = ($q2 ^ $q5 ^ $q7) & self::U32_MAX;
}
/**
* @param int $x
* @return int
*/
public static function subWord($x)
{
$q = ParagonIE_Sodium_Core_AES_Block::fromArray(
array($x, $x, $x, $x, $x, $x, $x, $x)
);
$q->orthogonalize();
self::sbox($q);
$q->orthogonalize();
return $q[0] & self::U32_MAX;
}
/**
* Calculate the key schedule from a given random key
*
* @param string $key
* @return ParagonIE_Sodium_Core_AES_KeySchedule
* @throws SodiumException
*/
public static function keySchedule($key)
{
$key_len = self::strlen($key);
switch ($key_len) {
case 16:
$num_rounds = 10;
break;
case 24:
$num_rounds = 12;
break;
case 32:
$num_rounds = 14;
break;
default:
throw new SodiumException('Invalid key length: ' . $key_len);
}
$skey = array();
$comp_skey = array();
$nk = $key_len >> 2;
$nkf = ($num_rounds + 1) << 2;
$tmp = 0;
for ($i = 0; $i < $nk; ++$i) {
$tmp = self::load_4(self::substr($key, $i << 2, 4));
$skey[($i << 1)] = $tmp;
$skey[($i << 1) + 1] = $tmp;
}
for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) {
if ($j === 0) {
$tmp = (($tmp & 0xff) << 24) | ($tmp >> 8);
$tmp = (self::subWord($tmp) ^ self::$Rcon[$k]) & self::U32_MAX;
} elseif ($nk > 6 && $j === 4) {
$tmp = self::subWord($tmp);
}
$tmp ^= $skey[($i - $nk) << 1];
$skey[($i << 1)] = $tmp & self::U32_MAX;
$skey[($i << 1) + 1] = $tmp & self::U32_MAX;
if (++$j === $nk) {
/** @psalm-suppress LoopInvalidation */
$j = 0;
++$k;
}
}
for ($i = 0; $i < $nkf; $i += 4) {
$q = ParagonIE_Sodium_Core_AES_Block::fromArray(
array_slice($skey, $i << 1, 8)
);
$q->orthogonalize();
// We have to overwrite $skey since we're not using C pointers like BearSSL did
for ($j = 0; $j < 8; ++$j) {
$skey[($i << 1) + $j] = $q[$j];
}
}
for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) {
$comp_skey[$i] = ($skey[$j] & 0x55555555)
| ($skey[$j + 1] & 0xAAAAAAAA);
}
return new ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds);
}
/**
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_KeySchedule $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @param int $offset
* @return void
*/
public static function addRoundKey(
ParagonIE_Sodium_Core_AES_Block $q,
ParagonIE_Sodium_Core_AES_KeySchedule $skey,
$offset = 0
) {
$block = $skey->getRoundKey($offset);
for ($j = 0; $j < 8; ++$j) {
$q[$j] = ($q[$j] ^ $block[$j]) & ParagonIE_Sodium_Core_Util::U32_MAX;
}
}
/**
* This mainly exists for testing, as we need the round key features for AEGIS.
*
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
*/
public static function decryptBlockECB($message, $key)
{
if (self::strlen($message) !== 16) {
throw new SodiumException('decryptBlockECB() expects a 16 byte message');
}
$skey = self::keySchedule($key)->expand();
$q = ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($message, 0, 4));
$q[2] = self::load_4(self::substr($message, 4, 4));
$q[4] = self::load_4(self::substr($message, 8, 4));
$q[6] = self::load_4(self::substr($message, 12, 4));
$q->orthogonalize();
self::bitsliceDecryptBlock($skey, $q);
$q->orthogonalize();
return self::store32_le($q[0]) .
self::store32_le($q[2]) .
self::store32_le($q[4]) .
self::store32_le($q[6]);
}
/**
* This mainly exists for testing, as we need the round key features for AEGIS.
*
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
*/
public static function encryptBlockECB($message, $key)
{
if (self::strlen($message) !== 16) {
throw new SodiumException('encryptBlockECB() expects a 16 byte message');
}
$comp_skey = self::keySchedule($key);
$skey = $comp_skey->expand();
$q = ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($message, 0, 4));
$q[2] = self::load_4(self::substr($message, 4, 4));
$q[4] = self::load_4(self::substr($message, 8, 4));
$q[6] = self::load_4(self::substr($message, 12, 4));
$q->orthogonalize();
self::bitsliceEncryptBlock($skey, $q);
$q->orthogonalize();
return self::store32_le($q[0]) .
self::store32_le($q[2]) .
self::store32_le($q[4]) .
self::store32_le($q[6]);
}
/**
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function bitsliceEncryptBlock(
ParagonIE_Sodium_Core_AES_Expanded $skey,
ParagonIE_Sodium_Core_AES_Block $q
) {
self::addRoundKey($q, $skey);
for ($u = 1; $u < $skey->getNumRounds(); ++$u) {
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
self::addRoundKey($q, $skey, ($u << 3));
}
self::sbox($q);
$q->shiftRows();
self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function aesRound($x, $y)
{
$q = ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($x, 0, 4));
$q[2] = self::load_4(self::substr($x, 4, 4));
$q[4] = self::load_4(self::substr($x, 8, 4));
$q[6] = self::load_4(self::substr($x, 12, 4));
$rk = ParagonIE_Sodium_Core_AES_Block::init();
$rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4));
$rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4));
$rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4));
$rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4));
$q->orthogonalize();
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
$q->orthogonalize();
// add round key without key schedule:
for ($i = 0; $i < 8; ++$i) {
$q[$i] ^= $rk[$i];
}
return self::store32_le($q[0]) .
self::store32_le($q[2]) .
self::store32_le($q[4]) .
self::store32_le($q[6]);
}
/**
* Process two AES blocks in one shot.
*
* @param string $b0 First AES block
* @param string $rk0 First round key
* @param string $b1 Second AES block
* @param string $rk1 Second round key
* @return string[]
*/
public static function doubleRound($b0, $rk0, $b1, $rk1)
{
$q = ParagonIE_Sodium_Core_AES_Block::init();
// First block
$q[0] = self::load_4(self::substr($b0, 0, 4));
$q[2] = self::load_4(self::substr($b0, 4, 4));
$q[4] = self::load_4(self::substr($b0, 8, 4));
$q[6] = self::load_4(self::substr($b0, 12, 4));
// Second block
$q[1] = self::load_4(self::substr($b1, 0, 4));
$q[3] = self::load_4(self::substr($b1, 4, 4));
$q[5] = self::load_4(self::substr($b1, 8, 4));
$q[7] = self::load_4(self::substr($b1, 12, 4));;
$rk = ParagonIE_Sodium_Core_AES_Block::init();
// First round key
$rk[0] = self::load_4(self::substr($rk0, 0, 4));
$rk[2] = self::load_4(self::substr($rk0, 4, 4));
$rk[4] = self::load_4(self::substr($rk0, 8, 4));
$rk[6] = self::load_4(self::substr($rk0, 12, 4));
// Second round key
$rk[1] = self::load_4(self::substr($rk1, 0, 4));
$rk[3] = self::load_4(self::substr($rk1, 4, 4));
$rk[5] = self::load_4(self::substr($rk1, 8, 4));
$rk[7] = self::load_4(self::substr($rk1, 12, 4));
$q->orthogonalize();
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
$q->orthogonalize();
// add round key without key schedule:
for ($i = 0; $i < 8; ++$i) {
$q[$i] ^= $rk[$i];
}
return array(
self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]),
self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]),
);
}
/**
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function bitsliceDecryptBlock(
ParagonIE_Sodium_Core_AES_Expanded $skey,
ParagonIE_Sodium_Core_AES_Block $q
) {
self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) {
$q->inverseShiftRows();
self::invSbox($q);
self::addRoundKey($q, $skey, ($u << 3));
$q->inverseMixColumns();
}
$q->inverseShiftRows();
self::invSbox($q);
self::addRoundKey($q, $skey, ($u << 3));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Fe', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Fe
*
* This represents a Field Element
*/
class ParagonIE_Sodium_Core_Curve25519_Fe implements ArrayAccess
{
/**
* @var array<int, int>
*/
protected $container = array();
/**
* @var int
*/
protected $size = 10;
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
*/
public static function fromArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
/** @var array<int, int> $keys */
$obj = new ParagonIE_Sodium_Core_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!is_int($value)) {
throw new InvalidArgumentException('Expected an integer');
}
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->container[$offset])) {
$this->container[$offset] = 0;
}
return (int) ($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
return array(implode(', ', $this->container));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_H', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_H
*
* This just contains the constants in the ref10/base.h file
*/
class ParagonIE_Sodium_Core_Curve25519_H extends ParagonIE_Sodium_Core_Util
{
/**
* See: libsodium's crypto_core/curve25519/ref10/base.h
*
* @var array<int, array<int, array<int, array<int, int>>>> Basically, int[32][8][3][10]
*/
protected static $base = array(
array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303),
array(-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081),
array(26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540),
array(23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397),
array(7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777),
array(-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737),
array(-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300),
),
array(
array(14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726),
array(-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955),
array(27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425),
),
),
array(
array(
array(-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171),
array(27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510),
array(17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660),
),
array(
array(-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639),
array(29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963),
array(5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950),
),
array(
array(-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568),
array(12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335),
array(25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628),
),
array(
array(-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007),
array(-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772),
array(-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653),
),
array(
array(2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567),
array(13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686),
array(21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372),
),
array(
array(-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887),
array(-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954),
array(-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953),
),
array(
array(24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833),
array(-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532),
array(-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876),
),
array(
array(2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268),
array(33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214),
array(1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038),
),
),
array(
array(
array(6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800),
array(4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645),
array(-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664),
),
array(
array(1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933),
array(-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182),
array(-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222),
),
array(
array(-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991),
array(20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880),
array(9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092),
),
array(
array(-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295),
array(19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788),
array(8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553),
),
array(
array(-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026),
array(11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347),
array(-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033),
),
array(
array(-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395),
array(-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278),
array(1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890),
),
array(
array(32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995),
array(-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596),
array(-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891),
),
array(
array(31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060),
array(11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608),
array(-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606),
),
),
array(
array(
array(7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389),
array(-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016),
array(-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341),
),
array(
array(-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505),
array(14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553),
array(-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655),
),
array(
array(15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220),
array(12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631),
array(-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099),
),
array(
array(26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556),
array(14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749),
array(236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930),
),
array(
array(1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391),
array(5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253),
array(20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066),
),
array(
array(24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958),
array(-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082),
array(-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383),
),
array(
array(-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521),
array(-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807),
array(23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948),
),
array(
array(9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134),
array(-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455),
array(27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629),
),
),
array(
array(
array(-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069),
array(-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746),
array(24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919),
),
array(
array(11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837),
array(8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906),
array(-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771),
),
array(
array(-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817),
array(10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098),
array(10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409),
),
array(
array(-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504),
array(-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727),
array(28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420),
),
array(
array(-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003),
array(-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605),
array(-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384),
),
array(
array(-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701),
array(-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683),
array(29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708),
),
array(
array(-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563),
array(-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260),
array(-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387),
),
array(
array(-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672),
array(23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686),
array(-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665),
),
),
array(
array(
array(11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182),
array(-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277),
array(14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628),
),
array(
array(-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474),
array(-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539),
array(-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822),
),
array(
array(-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970),
array(19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756),
array(-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508),
),
array(
array(-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683),
array(-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655),
array(-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158),
),
array(
array(-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125),
array(-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839),
array(-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664),
),
array(
array(27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294),
array(-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899),
array(-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070),
),
array(
array(3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294),
array(-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949),
array(-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083),
),
array(
array(31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420),
array(-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940),
array(29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396),
),
),
array(
array(
array(-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567),
array(20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127),
array(-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294),
),
array(
array(-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887),
array(22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964),
array(16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195),
),
array(
array(9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244),
array(24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999),
array(-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762),
),
array(
array(-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274),
array(-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236),
array(-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605),
),
array(
array(-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761),
array(-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884),
array(-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482),
),
array(
array(-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638),
array(-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490),
array(-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170),
),
array(
array(5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736),
array(10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124),
array(-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392),
),
array(
array(8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029),
array(6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048),
array(28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958),
),
),
array(
array(
array(24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593),
array(26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071),
array(-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692),
),
array(
array(11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687),
array(-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441),
array(-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001),
),
array(
array(-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460),
array(-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007),
array(-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762),
),
array(
array(15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005),
array(-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674),
array(4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035),
),
array(
array(7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590),
array(-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957),
array(-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812),
),
array(
array(33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740),
array(-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122),
array(-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158),
),
array(
array(8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885),
array(26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140),
array(19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857),
),
array(
array(801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155),
array(19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260),
array(19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483),
),
),
array(
array(
array(-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677),
array(32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815),
array(22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751),
),
array(
array(-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203),
array(-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208),
array(1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230),
),
array(
array(16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850),
array(-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389),
array(-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968),
),
array(
array(-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689),
array(14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880),
array(5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304),
),
array(
array(30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632),
array(-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412),
array(20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566),
),
array(
array(-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038),
array(-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232),
array(-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943),
),
array(
array(17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856),
array(23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738),
array(15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971),
),
array(
array(-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718),
array(-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697),
array(-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883),
),
),
array(
array(
array(5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912),
array(-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358),
array(3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849),
),
array(
array(29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307),
array(-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977),
array(-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335),
),
array(
array(-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644),
array(-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616),
array(-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735),
),
array(
array(-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099),
array(29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341),
array(-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336),
),
array(
array(-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646),
array(31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425),
array(-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388),
),
array(
array(-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743),
array(-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822),
array(-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462),
),
array(
array(18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985),
array(9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702),
array(-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797),
),
array(
array(21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293),
array(27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100),
array(19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688),
),
),
array(
array(
array(12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186),
array(2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610),
array(-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707),
),
array(
array(7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220),
array(915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025),
array(32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044),
),
array(
array(32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992),
array(-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027),
array(21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197),
),
array(
array(8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901),
array(31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952),
array(19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878),
),
array(
array(-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390),
array(32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730),
array(2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730),
),
array(
array(-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180),
array(-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272),
array(-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715),
),
array(
array(-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970),
array(-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772),
array(-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865),
),
array(
array(15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750),
array(20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373),
array(32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348),
),
),
array(
array(
array(9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144),
array(-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195),
array(5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086),
),
array(
array(-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684),
array(-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518),
array(-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233),
),
array(
array(-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793),
array(-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794),
array(580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435),
),
array(
array(23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921),
array(13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518),
array(2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563),
),
array(
array(14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278),
array(-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024),
array(4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030),
),
array(
array(10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783),
array(27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717),
array(6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844),
),
array(
array(14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333),
array(16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048),
array(22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760),
),
array(
array(-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760),
array(-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757),
array(-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112),
),
),
array(
array(
array(-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468),
array(3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184),
array(10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289),
),
array(
array(15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066),
array(24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882),
array(13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226),
),
array(
array(16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101),
array(29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279),
array(-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811),
),
array(
array(27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709),
array(20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714),
array(-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121),
),
array(
array(9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464),
array(12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847),
array(13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400),
),
array(
array(4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414),
array(-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158),
array(17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045),
),
array(
array(-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415),
array(-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459),
array(-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079),
),
array(
array(21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412),
array(-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743),
array(-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836),
),
),
array(
array(
array(12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022),
array(18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429),
array(-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065),
),
array(
array(30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861),
array(10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000),
array(-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101),
),
array(
array(32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815),
array(29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642),
array(10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966),
),
array(
array(25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574),
array(-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742),
array(-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689),
),
array(
array(12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020),
array(-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772),
array(3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982),
),
array(
array(-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953),
array(-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218),
array(-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265),
),
array(
array(29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073),
array(-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325),
array(-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798),
),
array(
array(-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870),
array(-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863),
array(-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927),
),
),
array(
array(
array(-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267),
array(-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663),
array(22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862),
),
array(
array(-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673),
array(15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943),
array(15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020),
),
array(
array(-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238),
array(11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064),
array(14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795),
),
array(
array(15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052),
array(-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904),
array(29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531),
),
array(
array(-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979),
array(-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841),
array(10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431),
),
array(
array(10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324),
array(-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940),
array(10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320),
),
array(
array(-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184),
array(14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114),
array(30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878),
),
array(
array(12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784),
array(-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091),
array(-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585),
),
),
array(
array(
array(-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208),
array(10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864),
array(17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661),
),
array(
array(7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233),
array(26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212),
array(-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525),
),
array(
array(-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068),
array(9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397),
array(-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988),
),
array(
array(5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889),
array(32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038),
array(14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697),
),
array(
array(20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875),
array(-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905),
array(-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656),
),
array(
array(11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818),
array(27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714),
array(10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203),
),
array(
array(20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931),
array(-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024),
array(-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084),
),
array(
array(-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204),
array(20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817),
array(27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667),
),
),
array(
array(
array(11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504),
array(-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768),
array(-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255),
),
array(
array(6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790),
array(1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438),
array(-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333),
),
array(
array(17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971),
array(31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905),
array(29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409),
),
array(
array(12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409),
array(6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499),
array(-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363),
),
array(
array(28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664),
array(-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324),
array(-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940),
),
array(
array(13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990),
array(-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914),
array(-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290),
),
array(
array(24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257),
array(-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433),
array(-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236),
),
array(
array(-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045),
array(11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093),
array(-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347),
),
),
array(
array(
array(-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191),
array(-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507),
array(-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906),
),
array(
array(3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018),
array(-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109),
array(-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926),
),
array(
array(-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528),
array(8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625),
array(-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286),
),
array(
array(2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033),
array(27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866),
array(21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896),
),
array(
array(30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075),
array(26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347),
array(-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437),
),
array(
array(-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165),
array(-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588),
array(-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193),
),
array(
array(-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017),
array(-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883),
array(21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961),
),
array(
array(8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043),
array(29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663),
array(-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362),
),
),
array(
array(
array(-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860),
array(2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466),
array(-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063),
),
array(
array(-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997),
array(-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295),
array(-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369),
),
array(
array(9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385),
array(18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109),
array(2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906),
),
array(
array(4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424),
array(-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185),
array(7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962),
),
array(
array(-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325),
array(10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593),
array(696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404),
),
array(
array(-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644),
array(17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801),
array(26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804),
),
array(
array(-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884),
array(-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577),
array(-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849),
),
array(
array(32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473),
array(-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644),
array(-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319),
),
),
array(
array(
array(-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599),
array(-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768),
array(-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084),
),
array(
array(-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328),
array(-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369),
array(20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920),
),
array(
array(12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815),
array(-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025),
array(-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397),
),
array(
array(-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448),
array(6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981),
array(30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165),
),
array(
array(32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501),
array(17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073),
array(-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861),
),
array(
array(14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845),
array(-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211),
array(18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870),
),
array(
array(10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096),
array(33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803),
array(-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168),
),
array(
array(30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965),
array(-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505),
array(18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598),
),
),
array(
array(
array(5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782),
array(5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900),
array(-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479),
),
array(
array(-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208),
array(8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232),
array(17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719),
),
array(
array(16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271),
array(-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326),
array(-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132),
),
array(
array(14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300),
array(8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570),
array(15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670),
),
array(
array(-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994),
array(-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913),
array(31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317),
),
array(
array(-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730),
array(842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096),
array(-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078),
),
array(
array(-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411),
array(-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905),
array(-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654),
),
array(
array(-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870),
array(-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498),
array(12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579),
),
),
array(
array(
array(14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677),
array(10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647),
array(-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743),
),
array(
array(-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468),
array(21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375),
array(-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155),
),
array(
array(6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725),
array(-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612),
array(-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943),
),
array(
array(-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944),
array(30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928),
array(9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406),
),
array(
array(22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139),
array(-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963),
array(-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693),
),
array(
array(1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734),
array(-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680),
array(-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410),
),
array(
array(-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931),
array(-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654),
array(22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710),
),
array(
array(29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180),
array(-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684),
array(-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895),
),
),
array(
array(
array(22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501),
array(-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413),
array(6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880),
),
array(
array(-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874),
array(22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962),
array(-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899),
),
array(
array(21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152),
array(9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063),
array(7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080),
),
array(
array(-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146),
array(-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183),
array(-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133),
),
array(
array(-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421),
array(-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622),
array(-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197),
),
array(
array(2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663),
array(31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753),
array(4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755),
),
array(
array(-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862),
array(-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118),
array(26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171),
),
array(
array(15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380),
array(16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824),
array(28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270),
),
),
array(
array(
array(-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438),
array(-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584),
array(-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562),
),
array(
array(30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471),
array(18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610),
array(19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269),
),
array(
array(-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650),
array(14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369),
array(19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461),
),
array(
array(30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462),
array(-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793),
array(-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218),
),
array(
array(-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226),
array(18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019),
array(-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037),
),
array(
array(31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171),
array(-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132),
array(-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841),
),
array(
array(21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181),
array(-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210),
array(-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040),
),
array(
array(3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935),
array(24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105),
array(-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814),
),
),
array(
array(
array(793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852),
array(5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581),
array(-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646),
),
array(
array(10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844),
array(10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025),
array(27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453),
),
array(
array(-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068),
array(4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192),
array(-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921),
),
array(
array(-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259),
array(-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426),
array(-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072),
),
array(
array(-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305),
array(13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832),
array(28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943),
),
array(
array(-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011),
array(24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447),
array(17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494),
),
array(
array(-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245),
array(-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859),
array(28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915),
),
array(
array(16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707),
array(10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848),
array(-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224),
),
),
array(
array(
array(-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391),
array(15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215),
array(-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101),
),
array(
array(23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713),
array(21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849),
array(-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930),
),
array(
array(-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940),
array(-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031),
array(-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404),
),
array(
array(-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243),
array(-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116),
array(-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525),
),
array(
array(-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509),
array(-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883),
array(15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865),
),
array(
array(-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660),
array(4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273),
array(-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138),
),
array(
array(-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560),
array(-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135),
array(2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941),
),
array(
array(-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739),
array(18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756),
array(-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819),
),
),
array(
array(
array(-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347),
array(-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028),
array(21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075),
),
array(
array(16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799),
array(-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609),
array(-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817),
),
array(
array(-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989),
array(-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523),
array(4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278),
),
array(
array(31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045),
array(19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377),
array(24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480),
),
array(
array(17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016),
array(510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426),
array(18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525),
),
array(
array(13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396),
array(9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080),
array(12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892),
),
array(
array(15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275),
array(11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074),
array(20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140),
),
array(
array(-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717),
array(-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101),
array(24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127),
),
),
array(
array(
array(-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632),
array(-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415),
array(-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160),
),
array(
array(31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876),
array(22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625),
array(-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478),
),
array(
array(27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164),
array(26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595),
array(-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248),
),
array(
array(-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858),
array(15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193),
array(8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184),
),
array(
array(-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942),
array(-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635),
array(21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948),
),
array(
array(11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935),
array(-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415),
array(-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416),
),
array(
array(-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018),
array(4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778),
array(366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659),
),
array(
array(-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385),
array(18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503),
array(476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329),
),
),
array(
array(
array(20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056),
array(-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838),
array(24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948),
),
array(
array(-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691),
array(-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118),
array(-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517),
),
array(
array(-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269),
array(-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904),
array(-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589),
),
array(
array(-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193),
array(-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910),
array(-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930),
),
array(
array(-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667),
array(25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481),
array(-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876),
),
array(
array(22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640),
array(-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278),
array(-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112),
),
array(
array(26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272),
array(17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012),
array(-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221),
),
array(
array(30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046),
array(13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345),
array(-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310),
),
),
array(
array(
array(19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937),
array(31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636),
array(-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008),
),
array(
array(-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429),
array(-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576),
array(31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066),
),
array(
array(-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490),
array(-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104),
array(33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053),
),
array(
array(31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275),
array(-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511),
array(22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095),
),
array(
array(-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439),
array(23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939),
array(-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424),
),
array(
array(2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310),
array(3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608),
array(-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079),
),
array(
array(-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101),
array(21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418),
array(18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576),
),
array(
array(30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356),
array(9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996),
array(-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099),
),
),
array(
array(
array(-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728),
array(-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658),
array(-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242),
),
array(
array(-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001),
array(-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766),
array(18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373),
),
array(
array(26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458),
array(-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628),
array(-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657),
),
array(
array(-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062),
array(25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616),
array(31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014),
),
array(
array(24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383),
array(-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814),
array(-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718),
),
array(
array(30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417),
array(2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222),
array(33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444),
),
array(
array(-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597),
array(23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970),
array(1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799),
),
array(
array(-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647),
array(13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511),
array(-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032),
),
),
array(
array(
array(9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834),
array(-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461),
array(29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062),
),
array(
array(-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516),
array(-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547),
array(-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240),
),
array(
array(-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038),
array(-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741),
array(16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103),
),
array(
array(-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747),
array(-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323),
array(31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016),
),
array(
array(-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373),
array(15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228),
array(-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141),
),
array(
array(16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399),
array(11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831),
array(-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376),
),
array(
array(-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313),
array(-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958),
array(-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577),
),
array(
array(-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743),
array(29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684),
array(-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476),
),
)
);
/**
* See: libsodium's crypto_core/curve25519/ref10/base2.h
*
* @var array basically int[8][3]
*/
protected static $base2 = array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300),
),
array(
array(-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877),
array(-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951),
array(4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784),
),
array(
array(-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436),
array(25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918),
array(23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877),
),
array(
array(-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800),
array(-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305),
array(-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300),
),
array(
array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876),
array(-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619),
array(-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683),
)
);
/**
* 37095705934669439343138083508754565189542113879843219016388785533085940283555
*
* @var array<int, int>
*/
protected static $d = array(
-10913610,
13857413,
-15372611,
6949391,
114729,
-8787816,
-6275908,
-3247719,
-18696448,
-12055116
);
/**
* 2 * d = 16295367250680780974490674513165176452449235426866156013048779062215315747161
*
* @var array<int, int>
*/
protected static $d2 = array(
-21827239,
-5839606,
-30745221,
13898782,
229458,
15978800,
-12551817,
-6495438,
29715968,
9444199
);
/**
* sqrt(-1)
*
* @var array<int, int>
*/
protected static $sqrtm1 = array(
-32595792,
-7943725,
9377950,
3500415,
12389472,
-272473,
-25146209,
-2005654,
326686,
11406482
);
/**
* 1 / sqrt(a - d)
*
* @var array<int, int>
*/
protected static $invsqrtamd = array(
6111485,
4156064,
-27798727,
12243468,
-25904040,
120897,
20826367,
-7060776,
6093568,
-1986012
);
/**
* sqrt(ad - 1) with a = -1 (mod p)
*
* @var array<int, int>
*/
protected static $sqrtadm1 = array(
24849947,
-153582,
-23613485,
6347715,
-21072328,
-667138,
-25271143,
-15367704,
-870347,
14525639
);
/**
* 1 - d ^ 2
*
* @var array<int, int>
*/
protected static $onemsqd = array(
6275446,
-16617371,
-22938544,
-3773710,
11667077,
7397348,
-27922721,
1766195,
-24433858,
672203
);
/**
* (d - 1) ^ 2
* @var array<int, int>
*/
protected static $sqdmone = array(
15551795,
-11097455,
-13425098,
-10125071,
-11896535,
10178284,
-26634327,
4729244,
-5282110,
-10116402
);
/*
* 2^252+27742317777372353535851937790883648493
static const unsigned char L[] = {
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
};
*/
const L = "\xed\xd3\xf5\x5c\x1a\x63\x12\x58\xd6\x9c\xf7\xa2\xde\xf9\xde\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10";
}
[02-Dec-2025 10:42:59 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Curve25519/H.php:12
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Curve25519/H.php on line 12
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Precomp', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $yplusx;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $yminusx;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $xy2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $yplusx
* @param ParagonIE_Sodium_Core_Curve25519_Fe $yminusx
* @param ParagonIE_Sodium_Core_Curve25519_Fe $xy2d
*/
public function __construct(
$yplusx = null,
$yminusx = null,
$xy2d = null
) {
if ($yplusx === null) {
$yplusx = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($yplusx instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($yminusx instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($xy2d instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->xy2d = $xy2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P1p1', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t
*/
public function __construct(
$x = null,
$y = null,
$z = null,
$t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($t instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Cached', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $YplusX;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $YminusX;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YplusX
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YminusX
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $Z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $T2d
*/
public function __construct(
$YplusX = null,
$YminusX = null,
$Z = null,
$T2d = null
) {
if ($YplusX === null) {
$YplusX = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($YplusX instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($YminusX instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($T2d instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->T2d = $T2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P3', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t
*/
public function __construct(
$x = null,
$y = null,
$z = null,
$t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($t instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P2', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
*/
public function __construct(
$x = null,
$y = null,
$z = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) {
throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $z;
}
}
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).
<?php
if (class_exists('ParagonIE_Sodium_Core_HChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core_HChaCha20 extends ParagonIE_Sodium_Core_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hChaCha20($in = '', $key = '', $c = null)
{
$ctx = array();
if ($c === null) {
$ctx[0] = 0x61707865;
$ctx[1] = 0x3320646e;
$ctx[2] = 0x79622d32;
$ctx[3] = 0x6b206574;
} else {
$ctx[0] = self::load_4(self::substr($c, 0, 4));
$ctx[1] = self::load_4(self::substr($c, 4, 4));
$ctx[2] = self::load_4(self::substr($c, 8, 4));
$ctx[3] = self::load_4(self::substr($c, 12, 4));
}
$ctx[4] = self::load_4(self::substr($key, 0, 4));
$ctx[5] = self::load_4(self::substr($key, 4, 4));
$ctx[6] = self::load_4(self::substr($key, 8, 4));
$ctx[7] = self::load_4(self::substr($key, 12, 4));
$ctx[8] = self::load_4(self::substr($key, 16, 4));
$ctx[9] = self::load_4(self::substr($key, 20, 4));
$ctx[10] = self::load_4(self::substr($key, 24, 4));
$ctx[11] = self::load_4(self::substr($key, 28, 4));
$ctx[12] = self::load_4(self::substr($in, 0, 4));
$ctx[13] = self::load_4(self::substr($in, 4, 4));
$ctx[14] = self::load_4(self::substr($in, 8, 4));
$ctx[15] = self::load_4(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx)
{
$x0 = (int) $ctx[0];
$x1 = (int) $ctx[1];
$x2 = (int) $ctx[2];
$x3 = (int) $ctx[3];
$x4 = (int) $ctx[4];
$x5 = (int) $ctx[5];
$x6 = (int) $ctx[6];
$x7 = (int) $ctx[7];
$x8 = (int) $ctx[8];
$x9 = (int) $ctx[9];
$x10 = (int) $ctx[10];
$x11 = (int) $ctx[11];
$x12 = (int) $ctx[12];
$x13 = (int) $ctx[13];
$x14 = (int) $ctx[14];
$x15 = (int) $ctx[15];
for ($i = 0; $i < 10; ++$i) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
return self::store32_le((int) ($x0 & 0xffffffff)) .
self::store32_le((int) ($x1 & 0xffffffff)) .
self::store32_le((int) ($x2 & 0xffffffff)) .
self::store32_le((int) ($x3 & 0xffffffff)) .
self::store32_le((int) ($x12 & 0xffffffff)) .
self::store32_le((int) ($x13 & 0xffffffff)) .
self::store32_le((int) ($x14 & 0xffffffff)) .
self::store32_le((int) ($x15 & 0xffffffff));
}
}
<?php
/**
* Class ParagonIE_Sodium_Core_Ristretto255
*/
class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519
{
const crypto_core_ristretto255_HASHBYTES = 64;
const HASH_SC_L = 48;
const CORE_H2C_SHA256 = 1;
const CORE_H2C_SHA512 = 2;
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_cneg(ParagonIE_Sodium_Core_Curve25519_Fe $f, $b)
{
$negf = self::fe_neg($f);
return self::fe_cmov($f, $negf, $b);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @throws SodiumException
*/
public static function fe_abs(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
return self::fe_cneg($f, self::fe_isnegative($f));
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return int
* @throws SodiumException
*/
public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
static $zero;
if ($zero === null) {
$zero = str_repeat("\x00", 32);
}
/** @var string $zero */
$str = self::fe_tobytes($f);
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($str[$i]);
}
return (($d - 1) >> 31) & 1;
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $u
* @param ParagonIE_Sodium_Core_Curve25519_Fe $v
* @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int}
*
* @throws SodiumException
*/
public static function ristretto255_sqrt_ratio_m1(
ParagonIE_Sodium_Core_Curve25519_Fe $u,
ParagonIE_Sodium_Core_Curve25519_Fe $v
) {
$sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
$v3 = self::fe_mul(
self::fe_sq($v),
$v
); /* v3 = v^3 */
$x = self::fe_mul(
self::fe_mul(
self::fe_sq($v3),
$u
),
$v
); /* x = uv^7 */
$x = self::fe_mul(
self::fe_mul(
self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */
$v3
),
$u
); /* x = uv^3(uv^7)^((q-5)/8) */
$vxx = self::fe_mul(
self::fe_sq($x),
$v
); /* vx^2 */
$m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */
$p_root_check = self::fe_add($vxx, $u); /* vx^2+u */
$f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */
$f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */
$has_m_root = self::fe_iszero($m_root_check);
$has_p_root = self::fe_iszero($p_root_check);
$has_f_root = self::fe_iszero($f_root_check);
$x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */
$x = self::fe_abs(
self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root)
);
return array(
'x' => $x,
'nonsquare' => $has_m_root | $has_p_root
);
}
/**
* @param string $s
* @return int
* @throws SodiumException
*/
public static function ristretto255_point_is_canonical($s)
{
$c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f;
for ($i = 30; $i > 0; --$i) {
$c |= self::chrToInt($s[$i]) ^ 0xff;
}
$c = ($c - 1) >> 8;
$d = (0xed - 1 - self::chrToInt($s[0])) >> 8;
$e = self::chrToInt($s[31]) >> 7;
return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1);
}
/**
* @param string $s
* @param bool $skipCanonicalCheck
* @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int}
* @throws SodiumException
*/
public static function ristretto255_frombytes($s, $skipCanonicalCheck = false)
{
if (!$skipCanonicalCheck) {
if (!self::ristretto255_point_is_canonical($s)) {
throw new SodiumException('S is not canonical');
}
}
$s_ = self::fe_frombytes($s);
$ss = self::fe_sq($s_); /* ss = s^2 */
$u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */
$u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */
$u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */
$u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */
$v = self::fe_mul(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d),
$u1u1
); /* v = d*u1^2 */
$v = self::fe_neg($v); /* v = -d*u1^2 */
$v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */
$v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */
// fe25519_1(one);
// notsquare = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2);
$one = self::fe_1();
$result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2);
$inv_sqrt = $result['x'];
$notsquare = $result['nonsquare'];
$h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
$h->X = self::fe_mul($inv_sqrt, $u2);
$h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v);
$h->X = self::fe_mul($h->X, $s_);
$h->X = self::fe_abs(
self::fe_add($h->X, $h->X)
);
$h->Y = self::fe_mul($u1, $h->Y);
$h->Z = self::fe_1();
$h->T = self::fe_mul($h->X, $h->Y);
$res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y));
return array('h' => $h, 'res' => $res);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
*/
public static function ristretto255_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
{
$sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
$invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$invsqrtamd);
$u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */
$zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */
$u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */
$u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */
$u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */
$one = self::fe_1();
// fe25519_1(one);
// (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2);
$result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2);
$inv_sqrt = $result['x'];
$den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */
$den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */
$z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */
$ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */
$iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */
$eden = self::fe_mul($den1, $invsqrtamd);
$t_z_inv = self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */
$rotate = self::fe_isnegative($t_z_inv);
$x_ = self::fe_copy($h->X);
$y_ = self::fe_copy($h->Y);
$den_inv = self::fe_copy($den2);
$x_ = self::fe_cmov($x_, $iy, $rotate);
$y_ = self::fe_cmov($y_, $ix, $rotate);
$den_inv = self::fe_cmov($den_inv, $eden, $rotate);
$x_z_inv = self::fe_mul($x_, $z_inv);
$y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv));
// fe25519_sub(s_, h->Z, y_);
// fe25519_mul(s_, den_inv, s_);
// fe25519_abs(s_, s_);
// fe25519_tobytes(s, s_);
return self::fe_tobytes(
self::fe_abs(
self::fe_mul(
$den_inv,
self::fe_sub($h->Z, $y_)
)
)
);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $t
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*
* @throws SodiumException
*/
public static function ristretto255_elligator(ParagonIE_Sodium_Core_Curve25519_Fe $t)
{
$sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
$onemsqd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$onemsqd);
$d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
$sqdmone = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqdmone);
$sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtadm1);
$one = self::fe_1();
$r = self::fe_mul($sqrtm1, self::fe_sq($t)); /* r = sqrt(-1)*t^2 */
$u = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */
$c = self::fe_neg(self::fe_1()); /* c = -1 */
$rpd = self::fe_add($r, $d); /* rpd = r+d */
$v = self::fe_mul(
self::fe_sub(
$c,
self::fe_mul($r, $d)
),
$rpd
); /* v = (c-r*d)*(r+d) */
$result = self::ristretto255_sqrt_ratio_m1($u, $v);
$s = $result['x'];
$wasnt_square = 1 - $result['nonsquare'];
$s_prime = self::fe_neg(
self::fe_abs(
self::fe_mul($s, $t)
)
); /* s_prime = -|s*t| */
$s = self::fe_cmov($s, $s_prime, $wasnt_square);
$c = self::fe_cmov($c, $r, $wasnt_square);
// fe25519_sub(n, r, one); /* n = r-1 */
// fe25519_mul(n, n, c); /* n = c*(r-1) */
// fe25519_mul(n, n, ed25519_sqdmone); /* n = c*(r-1)*(d-1)^2 */
// fe25519_sub(n, n, v); /* n = c*(r-1)*(d-1)^2-v */
$n = self::fe_sub(
self::fe_mul(
self::fe_mul(
self::fe_sub($r, $one),
$c
),
$sqdmone
),
$v
); /* n = c*(r-1)*(d-1)^2-v */
$w0 = self::fe_mul(
self::fe_add($s, $s),
$v
); /* w0 = 2s*v */
$w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */
$ss = self::fe_sq($s); /* ss = s^2 */
$w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */
$w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */
return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
self::fe_mul($w0, $w3),
self::fe_mul($w2, $w1),
self::fe_mul($w1, $w3),
self::fe_mul($w0, $w2)
);
}
/**
* @param string $h
* @return string
* @throws SodiumException
*/
public static function ristretto255_from_hash($h)
{
if (self::strlen($h) !== 64) {
throw new SodiumException('Hash must be 64 bytes');
}
//fe25519_frombytes(r0, h);
//fe25519_frombytes(r1, h + 32);
$r0 = self::fe_frombytes(self::substr($h, 0, 32));
$r1 = self::fe_frombytes(self::substr($h, 32, 32));
//ristretto255_elligator(&p0, r0);
//ristretto255_elligator(&p1, r1);
$p0 = self::ristretto255_elligator($r0);
$p1 = self::ristretto255_elligator($r1);
//ge25519_p3_to_cached(&p1_cached, &p1);
//ge25519_add_cached(&p_p1p1, &p0, &p1_cached);
$p_p1p1 = self::ge_add(
$p0,
self::ge_p3_to_cached($p1)
);
//ge25519_p1p1_to_p3(&p, &p_p1p1);
//ristretto255_p3_tobytes(s, &p);
return self::ristretto255_p3_tobytes(
self::ge_p1p1_to_p3($p_p1p1)
);
}
/**
* @param string $p
* @return int
* @throws SodiumException
*/
public static function is_valid_point($p)
{
$result = self::ristretto255_frombytes($p);
if ($result['res'] !== 0) {
return 0;
}
return 1;
}
/**
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
public static function ristretto255_add($p, $q)
{
$p_res = self::ristretto255_frombytes($p);
$q_res = self::ristretto255_frombytes($q);
if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
throw new SodiumException('Could not add points');
}
$p_p3 = $p_res['h'];
$q_p3 = $q_res['h'];
$q_cached = self::ge_p3_to_cached($q_p3);
$r_p1p1 = self::ge_add($p_p3, $q_cached);
$r_p3 = self::ge_p1p1_to_p3($r_p1p1);
return self::ristretto255_p3_tobytes($r_p3);
}
/**
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
public static function ristretto255_sub($p, $q)
{
$p_res = self::ristretto255_frombytes($p);
$q_res = self::ristretto255_frombytes($q);
if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
throw new SodiumException('Could not add points');
}
$p_p3 = $p_res['h'];
$q_p3 = $q_res['h'];
$q_cached = self::ge_p3_to_cached($q_p3);
$r_p1p1 = self::ge_sub($p_p3, $q_cached);
$r_p3 = self::ge_p1p1_to_p3($r_p1p1);
return self::ristretto255_p3_tobytes($r_p3);
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @return string
* @throws SodiumException
* @psalm-suppress PossiblyInvalidArgument hash API
*/
protected static function h2c_string_to_hash_sha256($hLen, $ctx, $msg)
{
$h = array_fill(0, $hLen, 0);
$ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0;
if ($hLen > 0xff) {
throw new SodiumException('Hash must be less than 256 bytes');
}
if ($ctx_len > 0xff) {
$st = hash_init('sha256');
self::hash_update($st, "H2C-OVERSIZE-DST-");
self::hash_update($st, $ctx);
$ctx = hash_final($st, true);
$ctx_len = 32;
}
$t = array(0, $hLen, 0);
$ux = str_repeat("\0", 64);
$st = hash_init('sha256');
self::hash_update($st, $ux);
self::hash_update($st, $msg);
self::hash_update($st, self::intArrayToString($t));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$u0 = hash_final($st, true);
for ($i = 0; $i < $hLen; $i += 64) {
$ux = self::xorStrings($ux, $u0);
++$t[2];
$st = hash_init('sha256');
self::hash_update($st, $ux);
self::hash_update($st, self::intToChr($t[2]));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$ux = hash_final($st, true);
$amount = min($hLen - $i, 64);
for ($j = 0; $j < $amount; ++$j) {
$h[$i + $j] = self::chrToInt($ux[$i]);
}
}
return self::intArrayToString(array_slice($h, 0, $hLen));
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @return string
* @throws SodiumException
* @psalm-suppress PossiblyInvalidArgument hash API
*/
protected static function h2c_string_to_hash_sha512($hLen, $ctx, $msg)
{
$h = array_fill(0, $hLen, 0);
$ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0;
if ($hLen > 0xff) {
throw new SodiumException('Hash must be less than 256 bytes');
}
if ($ctx_len > 0xff) {
$st = hash_init('sha256');
self::hash_update($st, "H2C-OVERSIZE-DST-");
self::hash_update($st, $ctx);
$ctx = hash_final($st, true);
$ctx_len = 32;
}
$t = array(0, $hLen, 0);
$ux = str_repeat("\0", 128);
$st = hash_init('sha512');
self::hash_update($st, $ux);
self::hash_update($st, $msg);
self::hash_update($st, self::intArrayToString($t));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$u0 = hash_final($st, true);
for ($i = 0; $i < $hLen; $i += 128) {
$ux = self::xorStrings($ux, $u0);
++$t[2];
$st = hash_init('sha512');
self::hash_update($st, $ux);
self::hash_update($st, self::intToChr($t[2]));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$ux = hash_final($st, true);
$amount = min($hLen - $i, 128);
for ($j = 0; $j < $amount; ++$j) {
$h[$i + $j] = self::chrToInt($ux[$i]);
}
}
return self::intArrayToString(array_slice($h, 0, $hLen));
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
public static function h2c_string_to_hash($hLen, $ctx, $msg, $hash_alg)
{
switch ($hash_alg) {
case self::CORE_H2C_SHA256:
return self::h2c_string_to_hash_sha256($hLen, $ctx, $msg);
case self::CORE_H2C_SHA512:
return self::h2c_string_to_hash_sha512($hLen, $ctx, $msg);
default:
throw new SodiumException('Invalid H2C hash algorithm');
}
}
/**
* @param ?string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
protected static function _string_to_element($ctx, $msg, $hash_alg)
{
return self::ristretto255_from_hash(
self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg)
);
}
/**
* @return string
* @throws SodiumException
* @throws Exception
*/
public static function ristretto255_random()
{
return self::ristretto255_from_hash(
ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES)
);
}
/**
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_random()
{
return self::scalar_random();
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_complement($s)
{
return self::scalar_complement($s);
}
/**
* @param string $s
* @return string
*/
public static function ristretto255_scalar_invert($s)
{
return self::sc25519_invert($s);
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_negate($s)
{
return self::scalar_negate($s);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_add($x, $y)
{
return self::scalar_add($x, $y);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_sub($x, $y)
{
return self::scalar_sub($x, $y);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_mul($x, $y)
{
return self::sc25519_mul($x, $y);
}
/**
* @param string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_from_string($ctx, $msg, $hash_alg)
{
$h = array_fill(0, 64, 0);
$h_be = self::stringToIntArray(
self::h2c_string_to_hash(
self::HASH_SC_L, $ctx, $msg, $hash_alg
)
);
for ($i = 0; $i < self::HASH_SC_L; ++$i) {
$h[$i] = $h_be[self::HASH_SC_L - 1 - $i];
}
return self::ristretto255_scalar_reduce(self::intArrayToString($h));
}
/**
* @param string $s
* @return string
*/
public static function ristretto255_scalar_reduce($s)
{
return self::sc_reduce($s);
}
/**
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255($n, $p)
{
if (self::strlen($n) !== 32) {
throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.');
}
if (self::strlen($p) !== 32) {
throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.');
}
$result = self::ristretto255_frombytes($p);
if ($result['res'] !== 0) {
throw new SodiumException('Could not multiply points');
}
$P = $result['h'];
$t = self::stringToIntArray($n);
$t[31] &= 0x7f;
$Q = self::ge_scalarmult(self::intArrayToString($t), $P);
$q = self::ristretto255_p3_tobytes($Q);
if (ParagonIE_Sodium_Compat::is_zero($q)) {
throw new SodiumException('An unknown error has occurred');
}
return $q;
}
/**
* @param string $n
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255_base($n)
{
$t = self::stringToIntArray($n);
$t[31] &= 0x7f;
$Q = self::ge_scalarmult_base(self::intArrayToString($t));
$q = self::ristretto255_p3_tobytes($Q);
if (ParagonIE_Sodium_Compat::is_zero($q)) {
throw new SodiumException('An unknown error has occurred');
}
return $q;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519
*
* Implements Curve25519 core functions
*
* Based on the ref10 curve25519 code provided by libsodium
*
* @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
*/
abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Curve25519_H
{
/**
* Get a field element of size 10 with a value of 0
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_0()
{
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
);
}
/**
* Get a field element of size 10 with a value of 1
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_1()
{
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
);
}
/**
* Add two field elements.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public static function fe_add(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g
) {
/** @var array<int, int> $arr */
$arr = array();
for ($i = 0; $i < 10; ++$i) {
$arr[$i] = (int) ($f[$i] + $g[$i]);
}
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr);
}
/**
* Constant-time conditional move.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedAssignment
*/
public static function fe_cmov(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g,
$b = 0
) {
/** @var array<int, int> $h */
$h = array();
$b *= -1;
for ($i = 0; $i < 10; ++$i) {
$x = (($f[$i] ^ $g[$i]) & $b);
$h[$i] = ($f[$i]) ^ $x;
}
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
}
/**
* Create a copy of a field element.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$h = clone $f;
return $h;
}
/**
* Give: 32-byte string.
* Receive: A field element object to use for internal calculations.
*
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @throws RangeException
* @throws TypeError
*/
public static function fe_frombytes($s)
{
if (self::strlen($s) !== 32) {
throw new RangeException('Expected a 32-byte string.');
}
$h0 = self::load_4($s);
$h1 = self::load_3(self::substr($s, 4, 3)) << 6;
$h2 = self::load_3(self::substr($s, 7, 3)) << 5;
$h3 = self::load_3(self::substr($s, 10, 3)) << 3;
$h4 = self::load_3(self::substr($s, 13, 3)) << 2;
$h5 = self::load_4(self::substr($s, 16, 4));
$h6 = self::load_3(self::substr($s, 20, 3)) << 7;
$h7 = self::load_3(self::substr($s, 23, 3)) << 5;
$h8 = self::load_3(self::substr($s, 26, 3)) << 4;
$h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2;
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
);
}
/**
* Convert a field element to a byte string.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $h
* @return string
*/
public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h)
{
$h0 = (int) $h[0];
$h1 = (int) $h[1];
$h2 = (int) $h[2];
$h3 = (int) $h[3];
$h4 = (int) $h[4];
$h5 = (int) $h[5];
$h6 = (int) $h[6];
$h7 = (int) $h[7];
$h8 = (int) $h[8];
$h9 = (int) $h[9];
$q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
$q = ($h0 + $q) >> 26;
$q = ($h1 + $q) >> 25;
$q = ($h2 + $q) >> 26;
$q = ($h3 + $q) >> 25;
$q = ($h4 + $q) >> 26;
$q = ($h5 + $q) >> 25;
$q = ($h6 + $q) >> 26;
$q = ($h7 + $q) >> 25;
$q = ($h8 + $q) >> 26;
$q = ($h9 + $q) >> 25;
$h0 += self::mul($q, 19, 5);
$carry0 = $h0 >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
$carry1 = $h1 >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
$carry2 = $h2 >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
$carry3 = $h3 >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
$carry4 = $h4 >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry5 = $h5 >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
$carry6 = $h6 >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
$carry7 = $h7 >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
$carry8 = $h8 >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
$carry9 = $h9 >> 25;
$h9 -= $carry9 << 25;
/**
* @var array<int, int>
*/
$s = array(
(int) (($h0 >> 0) & 0xff),
(int) (($h0 >> 8) & 0xff),
(int) (($h0 >> 16) & 0xff),
(int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
(int) (($h1 >> 6) & 0xff),
(int) (($h1 >> 14) & 0xff),
(int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
(int) (($h2 >> 5) & 0xff),
(int) (($h2 >> 13) & 0xff),
(int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
(int) (($h3 >> 3) & 0xff),
(int) (($h3 >> 11) & 0xff),
(int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
(int) (($h4 >> 2) & 0xff),
(int) (($h4 >> 10) & 0xff),
(int) (($h4 >> 18) & 0xff),
(int) (($h5 >> 0) & 0xff),
(int) (($h5 >> 8) & 0xff),
(int) (($h5 >> 16) & 0xff),
(int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
(int) (($h6 >> 7) & 0xff),
(int) (($h6 >> 15) & 0xff),
(int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
(int) (($h7 >> 5) & 0xff),
(int) (($h7 >> 13) & 0xff),
(int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
(int) (($h8 >> 4) & 0xff),
(int) (($h8 >> 12) & 0xff),
(int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
(int) (($h9 >> 2) & 0xff),
(int) (($h9 >> 10) & 0xff),
(int) (($h9 >> 18) & 0xff)
);
return self::intArrayToString($s);
}
/**
* Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$str = self::fe_tobytes($f);
return (int) (self::chrToInt($str[0]) & 1);
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
static $zero;
if ($zero === null) {
$zero = str_repeat("\x00", 32);
}
/** @var string $zero */
/** @var string $str */
$str = self::fe_tobytes($f);
return !self::verify_32($str, (string) $zero);
}
/**
* Multiply two field elements
*
* h = f * g
*
* @internal You should not use this directly from another application
*
* @security Is multiplication a source of timing leaks? If so, can we do
* anything to prevent that from happening?
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_mul(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g
) {
// Ensure limbs aren't oversized.
$f = self::fe_normalize($f);
$g = self::fe_normalize($g);
$f0 = $f[0];
$f1 = $f[1];
$f2 = $f[2];
$f3 = $f[3];
$f4 = $f[4];
$f5 = $f[5];
$f6 = $f[6];
$f7 = $f[7];
$f8 = $f[8];
$f9 = $f[9];
$g0 = $g[0];
$g1 = $g[1];
$g2 = $g[2];
$g3 = $g[3];
$g4 = $g[4];
$g5 = $g[5];
$g6 = $g[6];
$g7 = $g[7];
$g8 = $g[8];
$g9 = $g[9];
$g1_19 = self::mul($g1, 19, 5);
$g2_19 = self::mul($g2, 19, 5);
$g3_19 = self::mul($g3, 19, 5);
$g4_19 = self::mul($g4, 19, 5);
$g5_19 = self::mul($g5, 19, 5);
$g6_19 = self::mul($g6, 19, 5);
$g7_19 = self::mul($g7, 19, 5);
$g8_19 = self::mul($g8, 19, 5);
$g9_19 = self::mul($g9, 19, 5);
$f1_2 = $f1 << 1;
$f3_2 = $f3 << 1;
$f5_2 = $f5 << 1;
$f7_2 = $f7 << 1;
$f9_2 = $f9 << 1;
$f0g0 = self::mul($f0, $g0, 26);
$f0g1 = self::mul($f0, $g1, 25);
$f0g2 = self::mul($f0, $g2, 26);
$f0g3 = self::mul($f0, $g3, 25);
$f0g4 = self::mul($f0, $g4, 26);
$f0g5 = self::mul($f0, $g5, 25);
$f0g6 = self::mul($f0, $g6, 26);
$f0g7 = self::mul($f0, $g7, 25);
$f0g8 = self::mul($f0, $g8, 26);
$f0g9 = self::mul($f0, $g9, 26);
$f1g0 = self::mul($f1, $g0, 26);
$f1g1_2 = self::mul($f1_2, $g1, 25);
$f1g2 = self::mul($f1, $g2, 26);
$f1g3_2 = self::mul($f1_2, $g3, 25);
$f1g4 = self::mul($f1, $g4, 26);
$f1g5_2 = self::mul($f1_2, $g5, 25);
$f1g6 = self::mul($f1, $g6, 26);
$f1g7_2 = self::mul($f1_2, $g7, 25);
$f1g8 = self::mul($f1, $g8, 26);
$f1g9_38 = self::mul($g9_19, $f1_2, 26);
$f2g0 = self::mul($f2, $g0, 26);
$f2g1 = self::mul($f2, $g1, 25);
$f2g2 = self::mul($f2, $g2, 26);
$f2g3 = self::mul($f2, $g3, 25);
$f2g4 = self::mul($f2, $g4, 26);
$f2g5 = self::mul($f2, $g5, 25);
$f2g6 = self::mul($f2, $g6, 26);
$f2g7 = self::mul($f2, $g7, 25);
$f2g8_19 = self::mul($g8_19, $f2, 26);
$f2g9_19 = self::mul($g9_19, $f2, 26);
$f3g0 = self::mul($f3, $g0, 26);
$f3g1_2 = self::mul($f3_2, $g1, 25);
$f3g2 = self::mul($f3, $g2, 26);
$f3g3_2 = self::mul($f3_2, $g3, 25);
$f3g4 = self::mul($f3, $g4, 26);
$f3g5_2 = self::mul($f3_2, $g5, 25);
$f3g6 = self::mul($f3, $g6, 26);
$f3g7_38 = self::mul($g7_19, $f3_2, 26);
$f3g8_19 = self::mul($g8_19, $f3, 25);
$f3g9_38 = self::mul($g9_19, $f3_2, 26);
$f4g0 = self::mul($f4, $g0, 26);
$f4g1 = self::mul($f4, $g1, 25);
$f4g2 = self::mul($f4, $g2, 26);
$f4g3 = self::mul($f4, $g3, 25);
$f4g4 = self::mul($f4, $g4, 26);
$f4g5 = self::mul($f4, $g5, 25);
$f4g6_19 = self::mul($g6_19, $f4, 26);
$f4g7_19 = self::mul($g7_19, $f4, 26);
$f4g8_19 = self::mul($g8_19, $f4, 26);
$f4g9_19 = self::mul($g9_19, $f4, 26);
$f5g0 = self::mul($f5, $g0, 26);
$f5g1_2 = self::mul($f5_2, $g1, 25);
$f5g2 = self::mul($f5, $g2, 26);
$f5g3_2 = self::mul($f5_2, $g3, 25);
$f5g4 = self::mul($f5, $g4, 26);
$f5g5_38 = self::mul($g5_19, $f5_2, 26);
$f5g6_19 = self::mul($g6_19, $f5, 25);
$f5g7_38 = self::mul($g7_19, $f5_2, 26);
$f5g8_19 = self::mul($g8_19, $f5, 25);
$f5g9_38 = self::mul($g9_19, $f5_2, 26);
$f6g0 = self::mul($f6, $g0, 26);
$f6g1 = self::mul($f6, $g1, 25);
$f6g2 = self::mul($f6, $g2, 26);
$f6g3 = self::mul($f6, $g3, 25);
$f6g4_19 = self::mul($g4_19, $f6, 26);
$f6g5_19 = self::mul($g5_19, $f6, 26);
$f6g6_19 = self::mul($g6_19, $f6, 26);
$f6g7_19 = self::mul($g7_19, $f6, 26);
$f6g8_19 = self::mul($g8_19, $f6, 26);
$f6g9_19 = self::mul($g9_19, $f6, 26);
$f7g0 = self::mul($f7, $g0, 26);
$f7g1_2 = self::mul($f7_2, $g1, 25);
$f7g2 = self::mul($f7, $g2, 26);
$f7g3_38 = self::mul($g3_19, $f7_2, 26);
$f7g4_19 = self::mul($g4_19, $f7, 26);
$f7g5_38 = self::mul($g5_19, $f7_2, 26);
$f7g6_19 = self::mul($g6_19, $f7, 25);
$f7g7_38 = self::mul($g7_19, $f7_2, 26);
$f7g8_19 = self::mul($g8_19, $f7, 25);
$f7g9_38 = self::mul($g9_19,$f7_2, 26);
$f8g0 = self::mul($f8, $g0, 26);
$f8g1 = self::mul($f8, $g1, 25);
$f8g2_19 = self::mul($g2_19, $f8, 26);
$f8g3_19 = self::mul($g3_19, $f8, 26);
$f8g4_19 = self::mul($g4_19, $f8, 26);
$f8g5_19 = self::mul($g5_19, $f8, 26);
$f8g6_19 = self::mul($g6_19, $f8, 26);
$f8g7_19 = self::mul($g7_19, $f8, 26);
$f8g8_19 = self::mul($g8_19, $f8, 26);
$f8g9_19 = self::mul($g9_19, $f8, 26);
$f9g0 = self::mul($f9, $g0, 26);
$f9g1_38 = self::mul($g1_19, $f9_2, 26);
$f9g2_19 = self::mul($g2_19, $f9, 25);
$f9g3_38 = self::mul($g3_19, $f9_2, 26);
$f9g4_19 = self::mul($g4_19, $f9, 25);
$f9g5_38 = self::mul($g5_19, $f9_2, 26);
$f9g6_19 = self::mul($g6_19, $f9, 25);
$f9g7_38 = self::mul($g7_19, $f9_2, 26);
$f9g8_19 = self::mul($g8_19, $f9, 25);
$f9g9_38 = self::mul($g9_19, $f9_2, 26);
$h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
$h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
$h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
$h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
$h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
$h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
$h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38;
$h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19;
$h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38;
$h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
return self::fe_normalize(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
)
);
}
/**
* Get the negative values for each piece of the field element.
*
* h = -f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedAssignment
*/
public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$h = new ParagonIE_Sodium_Core_Curve25519_Fe();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = -$f[$i];
}
return self::fe_normalize($h);
}
/**
* Square a field element
*
* h = f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$f = self::fe_normalize($f);
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
$f0_2 = $f0 << 1;
$f1_2 = $f1 << 1;
$f2_2 = $f2 << 1;
$f3_2 = $f3 << 1;
$f4_2 = $f4 << 1;
$f5_2 = $f5 << 1;
$f6_2 = $f6 << 1;
$f7_2 = $f7 << 1;
$f5_38 = self::mul($f5, 38, 6);
$f6_19 = self::mul($f6, 19, 5);
$f7_38 = self::mul($f7, 38, 6);
$f8_19 = self::mul($f8, 19, 5);
$f9_38 = self::mul($f9, 38, 6);
$f0f0 = self::mul($f0, $f0, 26);
$f0f1_2 = self::mul($f0_2, $f1, 26);
$f0f2_2 = self::mul($f0_2, $f2, 26);
$f0f3_2 = self::mul($f0_2, $f3, 26);
$f0f4_2 = self::mul($f0_2, $f4, 26);
$f0f5_2 = self::mul($f0_2, $f5, 26);
$f0f6_2 = self::mul($f0_2, $f6, 26);
$f0f7_2 = self::mul($f0_2, $f7, 26);
$f0f8_2 = self::mul($f0_2, $f8, 26);
$f0f9_2 = self::mul($f0_2, $f9, 26);
$f1f1_2 = self::mul($f1_2, $f1, 26);
$f1f2_2 = self::mul($f1_2, $f2, 26);
$f1f3_4 = self::mul($f1_2, $f3_2, 26);
$f1f4_2 = self::mul($f1_2, $f4, 26);
$f1f5_4 = self::mul($f1_2, $f5_2, 26);
$f1f6_2 = self::mul($f1_2, $f6, 26);
$f1f7_4 = self::mul($f1_2, $f7_2, 26);
$f1f8_2 = self::mul($f1_2, $f8, 26);
$f1f9_76 = self::mul($f9_38, $f1_2, 27);
$f2f2 = self::mul($f2, $f2, 27);
$f2f3_2 = self::mul($f2_2, $f3, 27);
$f2f4_2 = self::mul($f2_2, $f4, 27);
$f2f5_2 = self::mul($f2_2, $f5, 27);
$f2f6_2 = self::mul($f2_2, $f6, 27);
$f2f7_2 = self::mul($f2_2, $f7, 27);
$f2f8_38 = self::mul($f8_19, $f2_2, 27);
$f2f9_38 = self::mul($f9_38, $f2, 26);
$f3f3_2 = self::mul($f3_2, $f3, 26);
$f3f4_2 = self::mul($f3_2, $f4, 26);
$f3f5_4 = self::mul($f3_2, $f5_2, 26);
$f3f6_2 = self::mul($f3_2, $f6, 26);
$f3f7_76 = self::mul($f7_38, $f3_2, 26);
$f3f8_38 = self::mul($f8_19, $f3_2, 26);
$f3f9_76 = self::mul($f9_38, $f3_2, 26);
$f4f4 = self::mul($f4, $f4, 26);
$f4f5_2 = self::mul($f4_2, $f5, 26);
$f4f6_38 = self::mul($f6_19, $f4_2, 27);
$f4f7_38 = self::mul($f7_38, $f4, 26);
$f4f8_38 = self::mul($f8_19, $f4_2, 27);
$f4f9_38 = self::mul($f9_38, $f4, 26);
$f5f5_38 = self::mul($f5_38, $f5, 26);
$f5f6_38 = self::mul($f6_19, $f5_2, 26);
$f5f7_76 = self::mul($f7_38, $f5_2, 26);
$f5f8_38 = self::mul($f8_19, $f5_2, 26);
$f5f9_76 = self::mul($f9_38, $f5_2, 26);
$f6f6_19 = self::mul($f6_19, $f6, 26);
$f6f7_38 = self::mul($f7_38, $f6, 26);
$f6f8_38 = self::mul($f8_19, $f6_2, 27);
$f6f9_38 = self::mul($f9_38, $f6, 26);
$f7f7_38 = self::mul($f7_38, $f7, 26);
$f7f8_38 = self::mul($f8_19, $f7_2, 26);
$f7f9_76 = self::mul($f9_38, $f7_2, 26);
$f8f8_19 = self::mul($f8_19, $f8, 26);
$f8f9_38 = self::mul($f9_38, $f8, 26);
$f9f9_38 = self::mul($f9_38, $f9, 26);
$h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38;
$h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
$h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19;
$h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38;
$h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38;
$h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38;
$h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19;
$h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38;
$h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38;
$h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
return self::fe_normalize(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
)
);
}
/**
* Square and double a field element
*
* h = 2 * f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$f = self::fe_normalize($f);
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
$f0_2 = $f0 << 1;
$f1_2 = $f1 << 1;
$f2_2 = $f2 << 1;
$f3_2 = $f3 << 1;
$f4_2 = $f4 << 1;
$f5_2 = $f5 << 1;
$f6_2 = $f6 << 1;
$f7_2 = $f7 << 1;
$f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
$f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
$f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
$f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
$f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
$f0f0 = self::mul($f0, $f0, 24);
$f0f1_2 = self::mul($f0_2, $f1, 24);
$f0f2_2 = self::mul($f0_2, $f2, 24);
$f0f3_2 = self::mul($f0_2, $f3, 24);
$f0f4_2 = self::mul($f0_2, $f4, 24);
$f0f5_2 = self::mul($f0_2, $f5, 24);
$f0f6_2 = self::mul($f0_2, $f6, 24);
$f0f7_2 = self::mul($f0_2, $f7, 24);
$f0f8_2 = self::mul($f0_2, $f8, 24);
$f0f9_2 = self::mul($f0_2, $f9, 24);
$f1f1_2 = self::mul($f1_2, $f1, 24);
$f1f2_2 = self::mul($f1_2, $f2, 24);
$f1f3_4 = self::mul($f1_2, $f3_2, 24);
$f1f4_2 = self::mul($f1_2, $f4, 24);
$f1f5_4 = self::mul($f1_2, $f5_2, 24);
$f1f6_2 = self::mul($f1_2, $f6, 24);
$f1f7_4 = self::mul($f1_2, $f7_2, 24);
$f1f8_2 = self::mul($f1_2, $f8, 24);
$f1f9_76 = self::mul($f9_38, $f1_2, 24);
$f2f2 = self::mul($f2, $f2, 24);
$f2f3_2 = self::mul($f2_2, $f3, 24);
$f2f4_2 = self::mul($f2_2, $f4, 24);
$f2f5_2 = self::mul($f2_2, $f5, 24);
$f2f6_2 = self::mul($f2_2, $f6, 24);
$f2f7_2 = self::mul($f2_2, $f7, 24);
$f2f8_38 = self::mul($f8_19, $f2_2, 25);
$f2f9_38 = self::mul($f9_38, $f2, 24);
$f3f3_2 = self::mul($f3_2, $f3, 24);
$f3f4_2 = self::mul($f3_2, $f4, 24);
$f3f5_4 = self::mul($f3_2, $f5_2, 24);
$f3f6_2 = self::mul($f3_2, $f6, 24);
$f3f7_76 = self::mul($f7_38, $f3_2, 24);
$f3f8_38 = self::mul($f8_19, $f3_2, 24);
$f3f9_76 = self::mul($f9_38, $f3_2, 24);
$f4f4 = self::mul($f4, $f4, 24);
$f4f5_2 = self::mul($f4_2, $f5, 24);
$f4f6_38 = self::mul($f6_19, $f4_2, 25);
$f4f7_38 = self::mul($f7_38, $f4, 24);
$f4f8_38 = self::mul($f8_19, $f4_2, 25);
$f4f9_38 = self::mul($f9_38, $f4, 24);
$f5f5_38 = self::mul($f5_38, $f5, 24);
$f5f6_38 = self::mul($f6_19, $f5_2, 24);
$f5f7_76 = self::mul($f7_38, $f5_2, 24);
$f5f8_38 = self::mul($f8_19, $f5_2, 24);
$f5f9_76 = self::mul($f9_38, $f5_2, 24);
$f6f6_19 = self::mul($f6_19, $f6, 24);
$f6f7_38 = self::mul($f7_38, $f6, 24);
$f6f8_38 = self::mul($f8_19, $f6_2, 25);
$f6f9_38 = self::mul($f9_38, $f6, 24);
$f7f7_38 = self::mul($f7_38, $f7, 24);
$f7f8_38 = self::mul($f8_19, $f7_2, 24);
$f7f9_76 = self::mul($f9_38, $f7_2, 24);
$f8f8_19 = self::mul($f8_19, $f8, 24);
$f8f9_38 = self::mul($f9_38, $f8, 24);
$f9f9_38 = self::mul($f9_38, $f9, 24);
$h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1;
$h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1;
$h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1;
$h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1;
$h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1;
$h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38) << 1;
$h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19) << 1;
$h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38) << 1;
$h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38) << 1;
$h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2) << 1;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
return self::fe_normalize(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z)
{
$z = clone $Z;
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t2 = self::fe_sq($t0);
$t1 = self::fe_mul($t1, $t2);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 20; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 100; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
return self::fe_mul($t1, $t0);
}
/**
* @internal You should not use this directly from another application
*
* @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $z
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z)
{
$z = self::fe_normalize($z);
# fe_sq(t0, z);
# fe_sq(t1, t0);
# fe_sq(t1, t1);
# fe_mul(t1, z, t1);
# fe_mul(t0, t0, t1);
# fe_sq(t0, t0);
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t0 = self::fe_sq($t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 5; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 20; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 20; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 100; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 100; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t0, t0);
# fe_sq(t0, t0);
# fe_mul(out, t0, z);
$t0 = self::fe_mul($t1, $t0);
$t0 = self::fe_sq($t0);
$t0 = self::fe_sq($t0);
return self::fe_mul($t0, $z);
}
/**
* Subtract two field elements.
*
* h = f - g
*
* Preconditions:
* |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
* |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
*
* Postconditions:
* |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedOperand
*/
public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g)
{
return self::fe_normalize(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) ($f[0] - $g[0]),
(int) ($f[1] - $g[1]),
(int) ($f[2] - $g[2]),
(int) ($f[3] - $g[3]),
(int) ($f[4] - $g[4]),
(int) ($f[5] - $g[5]),
(int) ($f[6] - $g[6]),
(int) ($f[7] - $g[7]),
(int) ($f[8] - $g[8]),
(int) ($f[9] - $g[9])
)
)
);
}
/**
* Add two group elements.
*
* r = p + q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_add(
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YplusX);
$r->Y = self::fe_mul($r->Y, $q->YminusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
* @param string $a
* @return array<int, mixed>
* @throws SodiumException
* @throws TypeError
*/
public static function slide($a)
{
if (self::strlen($a) < 256) {
if (self::strlen($a) < 16) {
$a = str_pad($a, 256, '0', STR_PAD_RIGHT);
}
}
/** @var array<int, int> $r */
$r = array();
/** @var int $i */
for ($i = 0; $i < 256; ++$i) {
$r[$i] = (int) (
1 & (
self::chrToInt($a[(int) ($i >> 3)])
>>
($i & 7)
)
);
}
for ($i = 0;$i < 256;++$i) {
if ($r[$i]) {
for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
if ($r[$i + $b]) {
if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
$r[$i] += $r[$i + $b] << $b;
$r[$i + $b] = 0;
} elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
$r[$i] -= $r[$i + $b] << $b;
for ($k = $i + $b; $k < 256; ++$k) {
if (!$r[$k]) {
$r[$k] = 1;
break;
}
$r[$k] = 0;
}
} else {
break;
}
}
}
}
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_frombytes_negate_vartime($s)
{
static $d = null;
if (!$d) {
$d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
}
# fe_frombytes(h->Y,s);
# fe_1(h->Z);
$h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
self::fe_0(),
self::fe_frombytes($s),
self::fe_1()
);
# fe_sq(u,h->Y);
# fe_mul(v,u,d);
# fe_sub(u,u,h->Z); /* u = y^2-1 */
# fe_add(v,v,h->Z); /* v = dy^2+1 */
$u = self::fe_sq($h->Y);
/** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
$v = self::fe_mul($u, $d);
$u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */
$v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
# fe_sq(v3,v);
# fe_mul(v3,v3,v); /* v3 = v^3 */
# fe_sq(h->X,v3);
# fe_mul(h->X,h->X,v);
# fe_mul(h->X,h->X,u); /* x = uv^7 */
$v3 = self::fe_sq($v);
$v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
$h->X = self::fe_sq($v3);
$h->X = self::fe_mul($h->X, $v);
$h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
# fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
# fe_mul(h->X,h->X,v3);
# fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
$h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
$h->X = self::fe_mul($h->X, $v3);
$h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */
# fe_sq(vxx,h->X);
# fe_mul(vxx,vxx,v);
# fe_sub(check,vxx,u); /* vx^2-u */
$vxx = self::fe_sq($h->X);
$vxx = self::fe_mul($vxx, $v);
$check = self::fe_sub($vxx, $u); /* vx^2 - u */
# if (fe_isnonzero(check)) {
# fe_add(check,vxx,u); /* vx^2+u */
# if (fe_isnonzero(check)) {
# return -1;
# }
# fe_mul(h->X,h->X,sqrtm1);
# }
if (self::fe_isnonzero($check)) {
$check = self::fe_add($vxx, $u); /* vx^2 + u */
if (self::fe_isnonzero($check)) {
throw new RangeException('Internal check failed.');
}
$h->X = self::fe_mul(
$h->X,
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
);
}
# if (fe_isnegative(h->X) == (s[31] >> 7)) {
# fe_neg(h->X,h->X);
# }
$i = self::chrToInt($s[31]);
if (self::fe_isnegative($h->X) === ($i >> 7)) {
$h->X = self::fe_neg($h->X);
}
# fe_mul(h->T,h->X,h->Y);
$h->T = self::fe_mul($h->X, $h->Y);
return $h;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_madd(
ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yplusx);
$r->Y = self::fe_mul($r->Y, $q->yminusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add(clone $p->Z, clone $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_msub(
ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yminusx);
$r->Y = self::fe_mul($r->Y, $q->yplusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add($p->Z, $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
$r->T = self::fe_mul($p->X, $p->Y);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
public static function ge_p2_0()
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
self::fe_0(),
self::fe_1(),
self::fe_1()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p)
{
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
$r->X = self::fe_sq($p->X);
$r->Z = self::fe_sq($p->Y);
$r->T = self::fe_sq2($p->Z);
$r->Y = self::fe_add($p->X, $p->Y);
$t0 = self::fe_sq($r->Y);
$r->Y = self::fe_add($r->Z, $r->X);
$r->Z = self::fe_sub($r->Z, $r->X);
$r->X = self::fe_sub($t0, $r->Y);
$r->T = self::fe_sub($r->T, $r->Z);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
public static function ge_p3_0()
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
self::fe_0(),
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
{
static $d2 = null;
if ($d2 === null) {
$d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
}
/** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
$r->YplusX = self::fe_add($p->Y, $p->X);
$r->YminusX = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_copy($p->Z);
$r->T2d = self::fe_mul($p->T, $d2);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
self::fe_copy($p->X),
self::fe_copy($p->Y),
self::fe_copy($p->Z)
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
{
$q = self::ge_p3_to_p2($p);
return self::ge_p2_dbl($q);
}
/**
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
public static function ge_precomp_0()
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $b
* @param int $c
* @return int
*/
public static function equal($b, $c)
{
return (int) ((($b ^ $c) - 1) >> 31) & 1;
}
/**
* @internal You should not use this directly from another application
*
* @param int|string $char
* @return int (1 = yes, 0 = no)
* @throws SodiumException
* @throws TypeError
*/
public static function negative($char)
{
if (is_int($char)) {
return ($char >> 63) & 1;
}
$x = self::chrToInt(self::substr($char, 0, 1));
return (int) ($x >> 63);
}
/**
* Conditional move
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
public static function cmov(
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
$b
) {
if (!is_int($b)) {
throw new InvalidArgumentException('Expected an integer.');
}
return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
self::fe_cmov($t->yplusx, $u->yplusx, $b),
self::fe_cmov($t->yminusx, $u->yminusx, $b),
self::fe_cmov($t->xy2d, $u->xy2d, $b)
);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
public static function ge_cmov_cached(
ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u,
$b
) {
$b &= 1;
$ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
$ret->YplusX = self::fe_cmov($t->YplusX, $u->YplusX, $b);
$ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b);
$ret->Z = self::fe_cmov($t->Z, $u->Z, $b);
$ret->T2d = self::fe_cmov($t->T2d, $u->T2d, $b);
return $ret;
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
* @throws SodiumException
*/
public static function ge_cmov8_cached(array $cached, $b)
{
// const unsigned char bnegative = negative(b);
// const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1));
$bnegative = self::negative($b);
$babs = $b - (((-$bnegative) & $b) << 1);
// ge25519_cached_0(t);
$t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
self::fe_1(),
self::fe_1(),
self::fe_1(),
self::fe_0()
);
// ge25519_cmov_cached(t, &cached[0], equal(babs, 1));
// ge25519_cmov_cached(t, &cached[1], equal(babs, 2));
// ge25519_cmov_cached(t, &cached[2], equal(babs, 3));
// ge25519_cmov_cached(t, &cached[3], equal(babs, 4));
// ge25519_cmov_cached(t, &cached[4], equal(babs, 5));
// ge25519_cmov_cached(t, &cached[5], equal(babs, 6));
// ge25519_cmov_cached(t, &cached[6], equal(babs, 7));
// ge25519_cmov_cached(t, &cached[7], equal(babs, 8));
for ($x = 0; $x < 8; ++$x) {
$t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1));
}
// fe25519_copy(minust.YplusX, t->YminusX);
// fe25519_copy(minust.YminusX, t->YplusX);
// fe25519_copy(minust.Z, t->Z);
// fe25519_neg(minust.T2d, t->T2d);
$minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
self::fe_copy($t->YminusX),
self::fe_copy($t->YplusX),
self::fe_copy($t->Z),
self::fe_neg($t->T2d)
);
return self::ge_cmov_cached($t, $minust, $bnegative);
}
/**
* @internal You should not use this directly from another application
*
* @param int $pos
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayOffset
*/
public static function ge_select($pos = 0, $b = 0)
{
static $base = null;
if ($base === null) {
$base = array();
/** @var int $i */
foreach (self::$base as $i => $bas) {
for ($j = 0; $j < 8; ++$j) {
$base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
);
}
}
}
/** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
if (!is_int($pos)) {
throw new InvalidArgumentException('Position must be an integer');
}
if ($pos < 0 || $pos > 31) {
throw new RangeException('Position is out of range [0, 31]');
}
$bnegative = self::negative($b);
$babs = $b - (((-$bnegative) & $b) << 1);
$t = self::ge_precomp_0();
for ($i = 0; $i < 8; ++$i) {
$t = self::cmov(
$t,
$base[$pos][$i],
self::equal($babs, $i + 1)
);
}
$minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
self::fe_copy($t->yminusx),
self::fe_copy($t->yplusx),
self::fe_neg($t->xy2d)
);
return self::cmov($t, $minusT, $bnegative);
}
/**
* Subtract two group elements.
*
* r = p - q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_sub(
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YminusX);
$r->Y = self::fe_mul($r->Y, $q->YplusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* Convert a group element to a byte string.
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
* @param string $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
*/
public static function ge_double_scalarmult_vartime(
$a,
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
$b
) {
/** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
$Ai = array();
/** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
static $Bi = array();
if (!$Bi) {
for ($i = 0; $i < 8; ++$i) {
$Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
);
}
}
for ($i = 0; $i < 8; ++$i) {
$Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
self::fe_0(),
self::fe_0(),
self::fe_0(),
self::fe_0()
);
}
# slide(aslide,a);
# slide(bslide,b);
/** @var array<int, int> $aslide */
$aslide = self::slide($a);
/** @var array<int, int> $bslide */
$bslide = self::slide($b);
# ge_p3_to_cached(&Ai[0],A);
# ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
$Ai[0] = self::ge_p3_to_cached($A);
$t = self::ge_p3_dbl($A);
$A2 = self::ge_p1p1_to_p3($t);
# ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
# ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
# ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
# ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
# ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
# ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
# ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
for ($i = 0; $i < 7; ++$i) {
$t = self::ge_add($A2, $Ai[$i]);
$u = self::ge_p1p1_to_p3($t);
$Ai[$i + 1] = self::ge_p3_to_cached($u);
}
# ge_p2_0(r);
$r = self::ge_p2_0();
# for (i = 255;i >= 0;--i) {
# if (aslide[i] || bslide[i]) break;
# }
$i = 255;
for (; $i >= 0; --$i) {
if ($aslide[$i] || $bslide[$i]) {
break;
}
}
# for (;i >= 0;--i) {
for (; $i >= 0; --$i) {
# ge_p2_dbl(&t,r);
$t = self::ge_p2_dbl($r);
# if (aslide[i] > 0) {
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_add(&t,&u,&Ai[aslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_add(
$u,
$Ai[(int) floor($aslide[$i] / 2)]
);
# } else if (aslide[i] < 0) {
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_sub(
$u,
$Ai[(int) floor(-$aslide[$i] / 2)]
);
}
# if (bslide[i] > 0) {
if ($bslide[$i] > 0) {
/** @var int $index */
$index = (int) floor($bslide[$i] / 2);
# ge_p1p1_to_p3(&u,&t);
# ge_madd(&t,&u,&Bi[bslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_madd($t, $u, $Bi[$index]);
# } else if (bslide[i] < 0) {
} elseif ($bslide[$i] < 0) {
/** @var int $index */
$index = (int) floor(-$bslide[$i] / 2);
# ge_p1p1_to_p3(&u,&t);
# ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_msub($t, $u, $Bi[$index]);
}
# ge_p1p1_to_p2(r,&t);
$r = self::ge_p1p1_to_p2($t);
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public static function ge_scalarmult($a, $p)
{
$e = array_fill(0, 64, 0);
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */
$pi = array();
// ge25519_p3_to_cached(&pi[1 - 1], p); /* p */
$pi[0] = self::ge_p3_to_cached($p);
// ge25519_p3_dbl(&t2, p);
// ge25519_p1p1_to_p3(&p2, &t2);
// ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */
$t2 = self::ge_p3_dbl($p);
$p2 = self::ge_p1p1_to_p3($t2);
$pi[1] = self::ge_p3_to_cached($p2);
// ge25519_add_cached(&t3, p, &pi[2 - 1]);
// ge25519_p1p1_to_p3(&p3, &t3);
// ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */
$t3 = self::ge_add($p, $pi[1]);
$p3 = self::ge_p1p1_to_p3($t3);
$pi[2] = self::ge_p3_to_cached($p3);
// ge25519_p3_dbl(&t4, &p2);
// ge25519_p1p1_to_p3(&p4, &t4);
// ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */
$t4 = self::ge_p3_dbl($p2);
$p4 = self::ge_p1p1_to_p3($t4);
$pi[3] = self::ge_p3_to_cached($p4);
// ge25519_add_cached(&t5, p, &pi[4 - 1]);
// ge25519_p1p1_to_p3(&p5, &t5);
// ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */
$t5 = self::ge_add($p, $pi[3]);
$p5 = self::ge_p1p1_to_p3($t5);
$pi[4] = self::ge_p3_to_cached($p5);
// ge25519_p3_dbl(&t6, &p3);
// ge25519_p1p1_to_p3(&p6, &t6);
// ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */
$t6 = self::ge_p3_dbl($p3);
$p6 = self::ge_p1p1_to_p3($t6);
$pi[5] = self::ge_p3_to_cached($p6);
// ge25519_add_cached(&t7, p, &pi[6 - 1]);
// ge25519_p1p1_to_p3(&p7, &t7);
// ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */
$t7 = self::ge_add($p, $pi[5]);
$p7 = self::ge_p1p1_to_p3($t7);
$pi[6] = self::ge_p3_to_cached($p7);
// ge25519_p3_dbl(&t8, &p4);
// ge25519_p1p1_to_p3(&p8, &t8);
// ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */
$t8 = self::ge_p3_dbl($p4);
$p8 = self::ge_p1p1_to_p3($t8);
$pi[7] = self::ge_p3_to_cached($p8);
// for (i = 0; i < 32; ++i) {
// e[2 * i + 0] = (a[i] >> 0) & 15;
// e[2 * i + 1] = (a[i] >> 4) & 15;
// }
for ($i = 0; $i < 32; ++$i) {
$e[($i << 1) ] = self::chrToInt($a[$i]) & 15;
$e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15;
}
// /* each e[i] is between 0 and 15 */
// /* e[63] is between 0 and 7 */
// carry = 0;
// for (i = 0; i < 63; ++i) {
// e[i] += carry;
// carry = e[i] + 8;
// carry >>= 4;
// e[i] -= carry * ((signed char) 1 << 4);
// }
$carry = 0;
for ($i = 0; $i < 63; ++$i) {
$e[$i] += $carry;
$carry = $e[$i] + 8;
$carry >>= 4;
$e[$i] -= $carry << 4;
}
// e[63] += carry;
// /* each e[i] is between -8 and 8 */
$e[63] += $carry;
// ge25519_p3_0(h);
$h = self::ge_p3_0();
// for (i = 63; i != 0; i--) {
for ($i = 63; $i != 0; --$i) {
// ge25519_cmov8_cached(&t, pi, e[i]);
$t = self::ge_cmov8_cached($pi, $e[$i]);
// ge25519_add_cached(&r, h, &t);
$r = self::ge_add($h, $t);
// ge25519_p1p1_to_p2(&s, &r);
// ge25519_p2_dbl(&r, &s);
// ge25519_p1p1_to_p2(&s, &r);
// ge25519_p2_dbl(&r, &s);
// ge25519_p1p1_to_p2(&s, &r);
// ge25519_p2_dbl(&r, &s);
// ge25519_p1p1_to_p2(&s, &r);
// ge25519_p2_dbl(&r, &s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
// ge25519_p1p1_to_p3(h, &r); /* *16 */
$h = self::ge_p1p1_to_p3($r); /* *16 */
}
// ge25519_cmov8_cached(&t, pi, e[i]);
// ge25519_add_cached(&r, h, &t);
// ge25519_p1p1_to_p3(h, &r);
$t = self::ge_cmov8_cached($pi, $e[0]);
$r = self::ge_add($h, $t);
return self::ge_p1p1_to_p3($r);
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public static function ge_scalarmult_base($a)
{
/** @var array<int, int> $e */
$e = array();
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
for ($i = 0; $i < 32; ++$i) {
$dbl = (int) $i << 1;
$e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
$e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
}
$carry = 0;
for ($i = 0; $i < 63; ++$i) {
$e[$i] += $carry;
$carry = $e[$i] + 8;
$carry >>= 4;
$e[$i] -= $carry << 4;
}
$e[63] += (int) $carry;
$h = self::ge_p3_0();
for ($i = 1; $i < 64; $i += 2) {
$t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
$r = self::ge_p3_dbl($h);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$h = self::ge_p1p1_to_p3($r);
for ($i = 0; $i < 64; $i += 2) {
$t = self::ge_select($i >> 1, (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
return $h;
}
/**
* Calculates (ab + c) mod l
* where l = 2^252 + 27742317777372353535851937790883648493
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @param string $c
* @return string
* @throws TypeError
*/
public static function sc_muladd($a, $b, $c)
{
$a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
$a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
$a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
$a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
$a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
$a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
$a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
$a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
$a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
$a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
$a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
$a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
$b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
$b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
$b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
$b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
$b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
$b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
$b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
$b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
$b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
$b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
$b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
$b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
$c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
$c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5);
$c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2);
$c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7);
$c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4);
$c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1);
$c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6);
$c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3);
$c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
$c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5);
$c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2);
$c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);
/* Can't really avoid the pyramid here: */
$s0 = $c0 + self::mul($a0, $b0, 24);
$s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
$s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24);
$s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
$s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
self::mul($a4, $b0, 24);
$s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
$s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24);
$s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
$s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
self::mul($a8, $b0, 24);
$s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
$s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24);
$s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
$s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24);
$s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
$s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
self::mul($a11, $b3, 24);
$s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
$s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24);
$s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
$s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
self::mul($a11, $b7, 24);
$s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
$s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24);
$s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
$s22 = self::mul($a11, $b11, 24);
$s23 = 0;
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
$carry18 = ($s18 + (1 << 20)) >> 21;
$s19 += $carry18;
$s18 -= $carry18 << 21;
$carry20 = ($s20 + (1 << 20)) >> 21;
$s21 += $carry20;
$s20 -= $carry20 << 21;
$carry22 = ($s22 + (1 << 20)) >> 21;
$s23 += $carry22;
$s22 -= $carry22 << 21;
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
$carry17 = ($s17 + (1 << 20)) >> 21;
$s18 += $carry17;
$s17 -= $carry17 << 21;
$carry19 = ($s19 + (1 << 20)) >> 21;
$s20 += $carry19;
$s19 -= $carry19 << 21;
$carry21 = ($s21 + (1 << 20)) >> 21;
$s22 += $carry21;
$s21 -= $carry21 << 21;
$s11 += self::mul($s23, 666643, 20);
$s12 += self::mul($s23, 470296, 19);
$s13 += self::mul($s23, 654183, 20);
$s14 -= self::mul($s23, 997805, 20);
$s15 += self::mul($s23, 136657, 18);
$s16 -= self::mul($s23, 683901, 20);
$s10 += self::mul($s22, 666643, 20);
$s11 += self::mul($s22, 470296, 19);
$s12 += self::mul($s22, 654183, 20);
$s13 -= self::mul($s22, 997805, 20);
$s14 += self::mul($s22, 136657, 18);
$s15 -= self::mul($s22, 683901, 20);
$s9 += self::mul($s21, 666643, 20);
$s10 += self::mul($s21, 470296, 19);
$s11 += self::mul($s21, 654183, 20);
$s12 -= self::mul($s21, 997805, 20);
$s13 += self::mul($s21, 136657, 18);
$s14 -= self::mul($s21, 683901, 20);
$s8 += self::mul($s20, 666643, 20);
$s9 += self::mul($s20, 470296, 19);
$s10 += self::mul($s20, 654183, 20);
$s11 -= self::mul($s20, 997805, 20);
$s12 += self::mul($s20, 136657, 18);
$s13 -= self::mul($s20, 683901, 20);
$s7 += self::mul($s19, 666643, 20);
$s8 += self::mul($s19, 470296, 19);
$s9 += self::mul($s19, 654183, 20);
$s10 -= self::mul($s19, 997805, 20);
$s11 += self::mul($s19, 136657, 18);
$s12 -= self::mul($s19, 683901, 20);
$s6 += self::mul($s18, 666643, 20);
$s7 += self::mul($s18, 470296, 19);
$s8 += self::mul($s18, 654183, 20);
$s9 -= self::mul($s18, 997805, 20);
$s10 += self::mul($s18, 136657, 18);
$s11 -= self::mul($s18, 683901, 20);
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
$s5 += self::mul($s17, 666643, 20);
$s6 += self::mul($s17, 470296, 19);
$s7 += self::mul($s17, 654183, 20);
$s8 -= self::mul($s17, 997805, 20);
$s9 += self::mul($s17, 136657, 18);
$s10 -= self::mul($s17, 683901, 20);
$s4 += self::mul($s16, 666643, 20);
$s5 += self::mul($s16, 470296, 19);
$s6 += self::mul($s16, 654183, 20);
$s7 -= self::mul($s16, 997805, 20);
$s8 += self::mul($s16, 136657, 18);
$s9 -= self::mul($s16, 683901, 20);
$s3 += self::mul($s15, 666643, 20);
$s4 += self::mul($s15, 470296, 19);
$s5 += self::mul($s15, 654183, 20);
$s6 -= self::mul($s15, 997805, 20);
$s7 += self::mul($s15, 136657, 18);
$s8 -= self::mul($s15, 683901, 20);
$s2 += self::mul($s14, 666643, 20);
$s3 += self::mul($s14, 470296, 19);
$s4 += self::mul($s14, 654183, 20);
$s5 -= self::mul($s14, 997805, 20);
$s6 += self::mul($s14, 136657, 18);
$s7 -= self::mul($s14, 683901, 20);
$s1 += self::mul($s13, 666643, 20);
$s2 += self::mul($s13, 470296, 19);
$s3 += self::mul($s13, 654183, 20);
$s4 -= self::mul($s13, 997805, 20);
$s5 += self::mul($s13, 136657, 18);
$s6 -= self::mul($s13, 683901, 20);
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry11 = $s11 >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/**
* @var array<int, int>
*/
$arr = array(
(int) (0xff & ($s0 >> 0)),
(int) (0xff & ($s0 >> 8)),
(int) (0xff & (($s0 >> 16) | $s1 << 5)),
(int) (0xff & ($s1 >> 3)),
(int) (0xff & ($s1 >> 11)),
(int) (0xff & (($s1 >> 19) | $s2 << 2)),
(int) (0xff & ($s2 >> 6)),
(int) (0xff & (($s2 >> 14) | $s3 << 7)),
(int) (0xff & ($s3 >> 1)),
(int) (0xff & ($s3 >> 9)),
(int) (0xff & (($s3 >> 17) | $s4 << 4)),
(int) (0xff & ($s4 >> 4)),
(int) (0xff & ($s4 >> 12)),
(int) (0xff & (($s4 >> 20) | $s5 << 1)),
(int) (0xff & ($s5 >> 7)),
(int) (0xff & (($s5 >> 15) | $s6 << 6)),
(int) (0xff & ($s6 >> 2)),
(int) (0xff & ($s6 >> 10)),
(int) (0xff & (($s6 >> 18) | $s7 << 3)),
(int) (0xff & ($s7 >> 5)),
(int) (0xff & ($s7 >> 13)),
(int) (0xff & ($s8 >> 0)),
(int) (0xff & ($s8 >> 8)),
(int) (0xff & (($s8 >> 16) | $s9 << 5)),
(int) (0xff & ($s9 >> 3)),
(int) (0xff & ($s9 >> 11)),
(int) (0xff & (($s9 >> 19) | $s10 << 2)),
(int) (0xff & ($s10 >> 6)),
(int) (0xff & (($s10 >> 14) | $s11 << 7)),
(int) (0xff & ($s11 >> 1)),
(int) (0xff & ($s11 >> 9)),
0xff & ($s11 >> 17)
);
return self::intArrayToString($arr);
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return string
* @throws TypeError
*/
public static function sc_reduce($s)
{
$s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
$s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5);
$s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2);
$s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7);
$s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4);
$s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1);
$s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6);
$s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3);
$s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
$s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5);
$s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2);
$s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7);
$s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4);
$s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1);
$s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6);
$s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3);
$s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
$s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5);
$s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2);
$s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7);
$s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4);
$s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1);
$s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6);
$s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3);
$s11 += self::mul($s23, 666643, 20);
$s12 += self::mul($s23, 470296, 19);
$s13 += self::mul($s23, 654183, 20);
$s14 -= self::mul($s23, 997805, 20);
$s15 += self::mul($s23, 136657, 18);
$s16 -= self::mul($s23, 683901, 20);
$s10 += self::mul($s22, 666643, 20);
$s11 += self::mul($s22, 470296, 19);
$s12 += self::mul($s22, 654183, 20);
$s13 -= self::mul($s22, 997805, 20);
$s14 += self::mul($s22, 136657, 18);
$s15 -= self::mul($s22, 683901, 20);
$s9 += self::mul($s21, 666643, 20);
$s10 += self::mul($s21, 470296, 19);
$s11 += self::mul($s21, 654183, 20);
$s12 -= self::mul($s21, 997805, 20);
$s13 += self::mul($s21, 136657, 18);
$s14 -= self::mul($s21, 683901, 20);
$s8 += self::mul($s20, 666643, 20);
$s9 += self::mul($s20, 470296, 19);
$s10 += self::mul($s20, 654183, 20);
$s11 -= self::mul($s20, 997805, 20);
$s12 += self::mul($s20, 136657, 18);
$s13 -= self::mul($s20, 683901, 20);
$s7 += self::mul($s19, 666643, 20);
$s8 += self::mul($s19, 470296, 19);
$s9 += self::mul($s19, 654183, 20);
$s10 -= self::mul($s19, 997805, 20);
$s11 += self::mul($s19, 136657, 18);
$s12 -= self::mul($s19, 683901, 20);
$s6 += self::mul($s18, 666643, 20);
$s7 += self::mul($s18, 470296, 19);
$s8 += self::mul($s18, 654183, 20);
$s9 -= self::mul($s18, 997805, 20);
$s10 += self::mul($s18, 136657, 18);
$s11 -= self::mul($s18, 683901, 20);
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
$s5 += self::mul($s17, 666643, 20);
$s6 += self::mul($s17, 470296, 19);
$s7 += self::mul($s17, 654183, 20);
$s8 -= self::mul($s17, 997805, 20);
$s9 += self::mul($s17, 136657, 18);
$s10 -= self::mul($s17, 683901, 20);
$s4 += self::mul($s16, 666643, 20);
$s5 += self::mul($s16, 470296, 19);
$s6 += self::mul($s16, 654183, 20);
$s7 -= self::mul($s16, 997805, 20);
$s8 += self::mul($s16, 136657, 18);
$s9 -= self::mul($s16, 683901, 20);
$s3 += self::mul($s15, 666643, 20);
$s4 += self::mul($s15, 470296, 19);
$s5 += self::mul($s15, 654183, 20);
$s6 -= self::mul($s15, 997805, 20);
$s7 += self::mul($s15, 136657, 18);
$s8 -= self::mul($s15, 683901, 20);
$s2 += self::mul($s14, 666643, 20);
$s3 += self::mul($s14, 470296, 19);
$s4 += self::mul($s14, 654183, 20);
$s5 -= self::mul($s14, 997805, 20);
$s6 += self::mul($s14, 136657, 18);
$s7 -= self::mul($s14, 683901, 20);
$s1 += self::mul($s13, 666643, 20);
$s2 += self::mul($s13, 470296, 19);
$s3 += self::mul($s13, 654183, 20);
$s4 -= self::mul($s13, 997805, 20);
$s5 += self::mul($s13, 136657, 18);
$s6 -= self::mul($s13, 683901, 20);
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$carry11 = $s11 >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/**
* @var array<int, int>
*/
$arr = array(
(int) ($s0 >> 0),
(int) ($s0 >> 8),
(int) (($s0 >> 16) | $s1 << 5),
(int) ($s1 >> 3),
(int) ($s1 >> 11),
(int) (($s1 >> 19) | $s2 << 2),
(int) ($s2 >> 6),
(int) (($s2 >> 14) | $s3 << 7),
(int) ($s3 >> 1),
(int) ($s3 >> 9),
(int) (($s3 >> 17) | $s4 << 4),
(int) ($s4 >> 4),
(int) ($s4 >> 12),
(int) (($s4 >> 20) | $s5 << 1),
(int) ($s5 >> 7),
(int) (($s5 >> 15) | $s6 << 6),
(int) ($s6 >> 2),
(int) ($s6 >> 10),
(int) (($s6 >> 18) | $s7 << 3),
(int) ($s7 >> 5),
(int) ($s7 >> 13),
(int) ($s8 >> 0),
(int) ($s8 >> 8),
(int) (($s8 >> 16) | $s9 << 5),
(int) ($s9 >> 3),
(int) ($s9 >> 11),
(int) (($s9 >> 19) | $s10 << 2),
(int) ($s10 >> 6),
(int) (($s10 >> 14) | $s11 << 7),
(int) ($s11 >> 1),
(int) ($s11 >> 9),
(int) $s11 >> 17
);
return self::intArrayToString($arr);
}
/**
* multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A)
{
$aslide = array(
13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
);
/** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
$Ai = array();
# ge_p3_to_cached(&Ai[0], A);
$Ai[0] = self::ge_p3_to_cached($A);
# ge_p3_dbl(&t, A);
$t = self::ge_p3_dbl($A);
# ge_p1p1_to_p3(&A2, &t);
$A2 = self::ge_p1p1_to_p3($t);
for ($i = 1; $i < 8; ++$i) {
# ge_add(&t, &A2, &Ai[0]);
$t = self::ge_add($A2, $Ai[$i - 1]);
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_p3_to_cached(&Ai[i], &u);
$Ai[$i] = self::ge_p3_to_cached($u);
}
$r = self::ge_p3_0();
for ($i = 252; $i >= 0; --$i) {
$t = self::ge_p3_dbl($r);
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_add(&t, &u, &Ai[aslide[i] / 2]);
$t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
$t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
}
}
# ge_p1p1_to_p3(r, &t);
return self::ge_p1p1_to_p3($t);
}
/**
* @param string $a
* @param string $b
* @return string
*/
public static function sc25519_mul($a, $b)
{
// int64_t a0 = 2097151 & load_3(a);
// int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
// int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
// int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
// int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
// int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
// int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
// int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
// int64_t a8 = 2097151 & load_3(a + 21);
// int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
// int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
// int64_t a11 = (load_4(a + 28) >> 7);
$a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
$a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
$a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
$a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
$a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
$a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
$a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
$a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
$a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
$a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
$a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
$a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
// int64_t b0 = 2097151 & load_3(b);
// int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
// int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
// int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
// int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
// int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
// int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
// int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
// int64_t b8 = 2097151 & load_3(b + 21);
// int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
// int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
// int64_t b11 = (load_4(b + 28) >> 7);
$b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
$b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
$b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
$b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
$b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
$b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
$b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
$b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
$b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
$b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
$b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
$b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
// s0 = a0 * b0;
// s1 = a0 * b1 + a1 * b0;
// s2 = a0 * b2 + a1 * b1 + a2 * b0;
// s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
// s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
// s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
// s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
// s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
// a6 * b1 + a7 * b0;
// s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
// a6 * b2 + a7 * b1 + a8 * b0;
// s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
// a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
// s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
// a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
// s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
// a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
// s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 +
// a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
// s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 +
// a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
// s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 +
// a9 * b5 + a10 * b4 + a11 * b3;
// s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 +
// a10 * b5 + a11 * b4;
// s16 =
// a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
// s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
// s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
// s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
// s20 = a9 * b11 + a10 * b10 + a11 * b9;
// s21 = a10 * b11 + a11 * b10;
// s22 = a11 * b11;
// s23 = 0;
$s0 = self::mul($a0, $b0, 22);
$s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22);
$s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22);
$s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22);
$s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) +
self::mul($a4, $b0, 22);
$s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) +
self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22);
$s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) +
self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22);
$s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) +
self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22);
$s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) +
self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) +
self::mul($a8, $b0, 22);
$s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) +
self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) +
self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22);
$s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) +
self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) +
self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22);
$s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) +
self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) +
self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22);
$s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) +
self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) +
self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22);
$s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) +
self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) +
self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22);
$s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) +
self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) +
self::mul($a11, $b3, 22);
$s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) +
self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22);
$s16 =
self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) +
self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22);
$s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) +
self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22);
$s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22)
+ self::mul($a11, $b7, 22);
$s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) +
self::mul($a11, $b8, 22);
$s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22);
$s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22);
$s22 = self::mul($a11, $b11, 22);
$s23 = 0;
// carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
// s1 += carry0;
// s0 -= carry0 * ((uint64_t) 1L << 21);
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
// carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
// s3 += carry2;
// s2 -= carry2 * ((uint64_t) 1L << 21);
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
// carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
// s5 += carry4;
// s4 -= carry4 * ((uint64_t) 1L << 21);
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
// carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
// s7 += carry6;
// s6 -= carry6 * ((uint64_t) 1L << 21);
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
// carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
// s9 += carry8;
// s8 -= carry8 * ((uint64_t) 1L << 21);
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
// carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
// s11 += carry10;
// s10 -= carry10 * ((uint64_t) 1L << 21);
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
// carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
// s13 += carry12;
// s12 -= carry12 * ((uint64_t) 1L << 21);
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
// carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
// s15 += carry14;
// s14 -= carry14 * ((uint64_t) 1L << 21);
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
// carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
// s17 += carry16;
// s16 -= carry16 * ((uint64_t) 1L << 21);
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
// carry18 = (s18 + (int64_t) (1L << 20)) >> 21;
// s19 += carry18;
// s18 -= carry18 * ((uint64_t) 1L << 21);
$carry18 = ($s18 + (1 << 20)) >> 21;
$s19 += $carry18;
$s18 -= $carry18 << 21;
// carry20 = (s20 + (int64_t) (1L << 20)) >> 21;
// s21 += carry20;
// s20 -= carry20 * ((uint64_t) 1L << 21);
$carry20 = ($s20 + (1 << 20)) >> 21;
$s21 += $carry20;
$s20 -= $carry20 << 21;
// carry22 = (s22 + (int64_t) (1L << 20)) >> 21;
// s23 += carry22;
// s22 -= carry22 * ((uint64_t) 1L << 21);
$carry22 = ($s22 + (1 << 20)) >> 21;
$s23 += $carry22;
$s22 -= $carry22 << 21;
// carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
// s2 += carry1;
// s1 -= carry1 * ((uint64_t) 1L << 21);
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
// carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
// s4 += carry3;
// s3 -= carry3 * ((uint64_t) 1L << 21);
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
// carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
// s6 += carry5;
// s5 -= carry5 * ((uint64_t) 1L << 21);
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
// carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
// s8 += carry7;
// s7 -= carry7 * ((uint64_t) 1L << 21);
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
// carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
// s10 += carry9;
// s9 -= carry9 * ((uint64_t) 1L << 21);
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
// carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
// s12 += carry11;
// s11 -= carry11 * ((uint64_t) 1L << 21);
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
// carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
// s14 += carry13;
// s13 -= carry13 * ((uint64_t) 1L << 21);
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
// carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
// s16 += carry15;
// s15 -= carry15 * ((uint64_t) 1L << 21);
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
// carry17 = (s17 + (int64_t) (1L << 20)) >> 21;
// s18 += carry17;
// s17 -= carry17 * ((uint64_t) 1L << 21);
$carry17 = ($s17 + (1 << 20)) >> 21;
$s18 += $carry17;
$s17 -= $carry17 << 21;
// carry19 = (s19 + (int64_t) (1L << 20)) >> 21;
// s20 += carry19;
// s19 -= carry19 * ((uint64_t) 1L << 21);
$carry19 = ($s19 + (1 << 20)) >> 21;
$s20 += $carry19;
$s19 -= $carry19 << 21;
// carry21 = (s21 + (int64_t) (1L << 20)) >> 21;
// s22 += carry21;
// s21 -= carry21 * ((uint64_t) 1L << 21);
$carry21 = ($s21 + (1 << 20)) >> 21;
$s22 += $carry21;
$s21 -= $carry21 << 21;
// s11 += s23 * 666643;
// s12 += s23 * 470296;
// s13 += s23 * 654183;
// s14 -= s23 * 997805;
// s15 += s23 * 136657;
// s16 -= s23 * 683901;
$s11 += self::mul($s23, 666643, 20);
$s12 += self::mul($s23, 470296, 19);
$s13 += self::mul($s23, 654183, 20);
$s14 -= self::mul($s23, 997805, 20);
$s15 += self::mul($s23, 136657, 18);
$s16 -= self::mul($s23, 683901, 20);
// s10 += s22 * 666643;
// s11 += s22 * 470296;
// s12 += s22 * 654183;
// s13 -= s22 * 997805;
// s14 += s22 * 136657;
// s15 -= s22 * 683901;
$s10 += self::mul($s22, 666643, 20);
$s11 += self::mul($s22, 470296, 19);
$s12 += self::mul($s22, 654183, 20);
$s13 -= self::mul($s22, 997805, 20);
$s14 += self::mul($s22, 136657, 18);
$s15 -= self::mul($s22, 683901, 20);
// s9 += s21 * 666643;
// s10 += s21 * 470296;
// s11 += s21 * 654183;
// s12 -= s21 * 997805;
// s13 += s21 * 136657;
// s14 -= s21 * 683901;
$s9 += self::mul($s21, 666643, 20);
$s10 += self::mul($s21, 470296, 19);
$s11 += self::mul($s21, 654183, 20);
$s12 -= self::mul($s21, 997805, 20);
$s13 += self::mul($s21, 136657, 18);
$s14 -= self::mul($s21, 683901, 20);
// s8 += s20 * 666643;
// s9 += s20 * 470296;
// s10 += s20 * 654183;
// s11 -= s20 * 997805;
// s12 += s20 * 136657;
// s13 -= s20 * 683901;
$s8 += self::mul($s20, 666643, 20);
$s9 += self::mul($s20, 470296, 19);
$s10 += self::mul($s20, 654183, 20);
$s11 -= self::mul($s20, 997805, 20);
$s12 += self::mul($s20, 136657, 18);
$s13 -= self::mul($s20, 683901, 20);
// s7 += s19 * 666643;
// s8 += s19 * 470296;
// s9 += s19 * 654183;
// s10 -= s19 * 997805;
// s11 += s19 * 136657;
// s12 -= s19 * 683901;
$s7 += self::mul($s19, 666643, 20);
$s8 += self::mul($s19, 470296, 19);
$s9 += self::mul($s19, 654183, 20);
$s10 -= self::mul($s19, 997805, 20);
$s11 += self::mul($s19, 136657, 18);
$s12 -= self::mul($s19, 683901, 20);
// s6 += s18 * 666643;
// s7 += s18 * 470296;
// s8 += s18 * 654183;
// s9 -= s18 * 997805;
// s10 += s18 * 136657;
// s11 -= s18 * 683901;
$s6 += self::mul($s18, 666643, 20);
$s7 += self::mul($s18, 470296, 19);
$s8 += self::mul($s18, 654183, 20);
$s9 -= self::mul($s18, 997805, 20);
$s10 += self::mul($s18, 136657, 18);
$s11 -= self::mul($s18, 683901, 20);
// carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
// s7 += carry6;
// s6 -= carry6 * ((uint64_t) 1L << 21);
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
// carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
// s9 += carry8;
// s8 -= carry8 * ((uint64_t) 1L << 21);
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
// carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
// s11 += carry10;
// s10 -= carry10 * ((uint64_t) 1L << 21);
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
// carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
// s13 += carry12;
// s12 -= carry12 * ((uint64_t) 1L << 21);
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
// carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
// s15 += carry14;
// s14 -= carry14 * ((uint64_t) 1L << 21);
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
// carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
// s17 += carry16;
// s16 -= carry16 * ((uint64_t) 1L << 21);
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
// carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
// s8 += carry7;
// s7 -= carry7 * ((uint64_t) 1L << 21);
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
// carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
// s10 += carry9;
// s9 -= carry9 * ((uint64_t) 1L << 21);
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
// carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
// s12 += carry11;
// s11 -= carry11 * ((uint64_t) 1L << 21);
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
// carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
// s14 += carry13;
// s13 -= carry13 * ((uint64_t) 1L << 21);
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
// carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
// s16 += carry15;
// s15 -= carry15 * ((uint64_t) 1L << 21);
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
// s5 += s17 * 666643;
// s6 += s17 * 470296;
// s7 += s17 * 654183;
// s8 -= s17 * 997805;
// s9 += s17 * 136657;
// s10 -= s17 * 683901;
$s5 += self::mul($s17, 666643, 20);
$s6 += self::mul($s17, 470296, 19);
$s7 += self::mul($s17, 654183, 20);
$s8 -= self::mul($s17, 997805, 20);
$s9 += self::mul($s17, 136657, 18);
$s10 -= self::mul($s17, 683901, 20);
// s4 += s16 * 666643;
// s5 += s16 * 470296;
// s6 += s16 * 654183;
// s7 -= s16 * 997805;
// s8 += s16 * 136657;
// s9 -= s16 * 683901;
$s4 += self::mul($s16, 666643, 20);
$s5 += self::mul($s16, 470296, 19);
$s6 += self::mul($s16, 654183, 20);
$s7 -= self::mul($s16, 997805, 20);
$s8 += self::mul($s16, 136657, 18);
$s9 -= self::mul($s16, 683901, 20);
// s3 += s15 * 666643;
// s4 += s15 * 470296;
// s5 += s15 * 654183;
// s6 -= s15 * 997805;
// s7 += s15 * 136657;
// s8 -= s15 * 683901;
$s3 += self::mul($s15, 666643, 20);
$s4 += self::mul($s15, 470296, 19);
$s5 += self::mul($s15, 654183, 20);
$s6 -= self::mul($s15, 997805, 20);
$s7 += self::mul($s15, 136657, 18);
$s8 -= self::mul($s15, 683901, 20);
// s2 += s14 * 666643;
// s3 += s14 * 470296;
// s4 += s14 * 654183;
// s5 -= s14 * 997805;
// s6 += s14 * 136657;
// s7 -= s14 * 683901;
$s2 += self::mul($s14, 666643, 20);
$s3 += self::mul($s14, 470296, 19);
$s4 += self::mul($s14, 654183, 20);
$s5 -= self::mul($s14, 997805, 20);
$s6 += self::mul($s14, 136657, 18);
$s7 -= self::mul($s14, 683901, 20);
// s1 += s13 * 666643;
// s2 += s13 * 470296;
// s3 += s13 * 654183;
// s4 -= s13 * 997805;
// s5 += s13 * 136657;
// s6 -= s13 * 683901;
$s1 += self::mul($s13, 666643, 20);
$s2 += self::mul($s13, 470296, 19);
$s3 += self::mul($s13, 654183, 20);
$s4 -= self::mul($s13, 997805, 20);
$s5 += self::mul($s13, 136657, 18);
$s6 -= self::mul($s13, 683901, 20);
// s0 += s12 * 666643;
// s1 += s12 * 470296;
// s2 += s12 * 654183;
// s3 -= s12 * 997805;
// s4 += s12 * 136657;
// s5 -= s12 * 683901;
// s12 = 0;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
// carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
// s1 += carry0;
// s0 -= carry0 * ((uint64_t) 1L << 21);
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
// carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
// s3 += carry2;
// s2 -= carry2 * ((uint64_t) 1L << 21);
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
// carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
// s5 += carry4;
// s4 -= carry4 * ((uint64_t) 1L << 21);
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
// carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
// s7 += carry6;
// s6 -= carry6 * ((uint64_t) 1L << 21);
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
// carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
// s9 += carry8;
// s8 -= carry8 * ((uint64_t) 1L << 21);
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
// carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
// s11 += carry10;
// s10 -= carry10 * ((uint64_t) 1L << 21);
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
// carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
// s2 += carry1;
// s1 -= carry1 * ((uint64_t) 1L << 21);
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
// carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
// s4 += carry3;
// s3 -= carry3 * ((uint64_t) 1L << 21);
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
// carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
// s6 += carry5;
// s5 -= carry5 * ((uint64_t) 1L << 21);
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
// carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
// s8 += carry7;
// s7 -= carry7 * ((uint64_t) 1L << 21);
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
// carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
// s10 += carry9;
// s9 -= carry9 * ((uint64_t) 1L << 21);
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
// carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
// s12 += carry11;
// s11 -= carry11 * ((uint64_t) 1L << 21);
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
// s0 += s12 * 666643;
// s1 += s12 * 470296;
// s2 += s12 * 654183;
// s3 -= s12 * 997805;
// s4 += s12 * 136657;
// s5 -= s12 * 683901;
// s12 = 0;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
// carry0 = s0 >> 21;
// s1 += carry0;
// s0 -= carry0 * ((uint64_t) 1L << 21);
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
// carry1 = s1 >> 21;
// s2 += carry1;
// s1 -= carry1 * ((uint64_t) 1L << 21);
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
// carry2 = s2 >> 21;
// s3 += carry2;
// s2 -= carry2 * ((uint64_t) 1L << 21);
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
// carry3 = s3 >> 21;
// s4 += carry3;
// s3 -= carry3 * ((uint64_t) 1L << 21);
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
// carry4 = s4 >> 21;
// s5 += carry4;
// s4 -= carry4 * ((uint64_t) 1L << 21);
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
// carry5 = s5 >> 21;
// s6 += carry5;
// s5 -= carry5 * ((uint64_t) 1L << 21);
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
// carry6 = s6 >> 21;
// s7 += carry6;
// s6 -= carry6 * ((uint64_t) 1L << 21);
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
// carry7 = s7 >> 21;
// s8 += carry7;
// s7 -= carry7 * ((uint64_t) 1L << 21);
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
// carry8 = s8 >> 21;
// s9 += carry8;
// s8 -= carry8 * ((uint64_t) 1L << 21);
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
// carry9 = s9 >> 21;
// s10 += carry9;
// s9 -= carry9 * ((uint64_t) 1L << 21);
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
// carry10 = s10 >> 21;
// s11 += carry10;
// s10 -= carry10 * ((uint64_t) 1L << 21);
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
// carry11 = s11 >> 21;
// s12 += carry11;
// s11 -= carry11 * ((uint64_t) 1L << 21);
$carry11 = $s11 >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
// s0 += s12 * 666643;
// s1 += s12 * 470296;
// s2 += s12 * 654183;
// s3 -= s12 * 997805;
// s4 += s12 * 136657;
// s5 -= s12 * 683901;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
// carry0 = s0 >> 21;
// s1 += carry0;
// s0 -= carry0 * ((uint64_t) 1L << 21);
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
// carry1 = s1 >> 21;
// s2 += carry1;
// s1 -= carry1 * ((uint64_t) 1L << 21);
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
// carry2 = s2 >> 21;
// s3 += carry2;
// s2 -= carry2 * ((uint64_t) 1L << 21);
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
// carry3 = s3 >> 21;
// s4 += carry3;
// s3 -= carry3 * ((uint64_t) 1L << 21);
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
// carry4 = s4 >> 21;
// s5 += carry4;
// s4 -= carry4 * ((uint64_t) 1L << 21);
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
// carry5 = s5 >> 21;
// s6 += carry5;
// s5 -= carry5 * ((uint64_t) 1L << 21);
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
// carry6 = s6 >> 21;
// s7 += carry6;
// s6 -= carry6 * ((uint64_t) 1L << 21);
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
// carry7 = s7 >> 21;
// s8 += carry7;
// s7 -= carry7 * ((uint64_t) 1L << 21);
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
// carry8 = s8 >> 21;
// s9 += carry8;
// s8 -= carry8 * ((uint64_t) 1L << 21);
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
// carry9 = s9 >> 21;
// s10 += carry9;
// s9 -= carry9 * ((uint64_t) 1L << 21);
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
// carry10 = s10 >> 21;
// s11 += carry10;
// s10 -= carry10 * ((uint64_t) 1L << 21);
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
$s = array_fill(0, 32, 0);
// s[0] = s0 >> 0;
$s[0] = $s0 >> 0;
// s[1] = s0 >> 8;
$s[1] = $s0 >> 8;
// s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5));
$s[2] = ($s0 >> 16) | ($s1 << 5);
// s[3] = s1 >> 3;
$s[3] = $s1 >> 3;
// s[4] = s1 >> 11;
$s[4] = $s1 >> 11;
// s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2));
$s[5] = ($s1 >> 19) | ($s2 << 2);
// s[6] = s2 >> 6;
$s[6] = $s2 >> 6;
// s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7));
$s[7] = ($s2 >> 14) | ($s3 << 7);
// s[8] = s3 >> 1;
$s[8] = $s3 >> 1;
// s[9] = s3 >> 9;
$s[9] = $s3 >> 9;
// s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4));
$s[10] = ($s3 >> 17) | ($s4 << 4);
// s[11] = s4 >> 4;
$s[11] = $s4 >> 4;
// s[12] = s4 >> 12;
$s[12] = $s4 >> 12;
// s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1));
$s[13] = ($s4 >> 20) | ($s5 << 1);
// s[14] = s5 >> 7;
$s[14] = $s5 >> 7;
// s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6));
$s[15] = ($s5 >> 15) | ($s6 << 6);
// s[16] = s6 >> 2;
$s[16] = $s6 >> 2;
// s[17] = s6 >> 10;
$s[17] = $s6 >> 10;
// s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3));
$s[18] = ($s6 >> 18) | ($s7 << 3);
// s[19] = s7 >> 5;
$s[19] = $s7 >> 5;
// s[20] = s7 >> 13;
$s[20] = $s7 >> 13;
// s[21] = s8 >> 0;
$s[21] = $s8 >> 0;
// s[22] = s8 >> 8;
$s[22] = $s8 >> 8;
// s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5));
$s[23] = ($s8 >> 16) | ($s9 << 5);
// s[24] = s9 >> 3;
$s[24] = $s9 >> 3;
// s[25] = s9 >> 11;
$s[25] = $s9 >> 11;
// s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2));
$s[26] = ($s9 >> 19) | ($s10 << 2);
// s[27] = s10 >> 6;
$s[27] = $s10 >> 6;
// s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7));
$s[28] = ($s10 >> 14) | ($s11 << 7);
// s[29] = s11 >> 1;
$s[29] = $s11 >> 1;
// s[30] = s11 >> 9;
$s[30] = $s11 >> 9;
// s[31] = s11 >> 17;
$s[31] = $s11 >> 17;
return self::intArrayToString($s);
}
/**
* @param string $s
* @return string
*/
public static function sc25519_sq($s)
{
return self::sc25519_mul($s, $s);
}
/**
* @param string $s
* @param int $n
* @param string $a
* @return string
*/
public static function sc25519_sqmul($s, $n, $a)
{
for ($i = 0; $i < $n; ++$i) {
$s = self::sc25519_sq($s);
}
return self::sc25519_mul($s, $a);
}
/**
* @param string $s
* @return string
*/
public static function sc25519_invert($s)
{
$_10 = self::sc25519_sq($s);
$_11 = self::sc25519_mul($s, $_10);
$_100 = self::sc25519_mul($s, $_11);
$_1000 = self::sc25519_sq($_100);
$_1010 = self::sc25519_mul($_10, $_1000);
$_1011 = self::sc25519_mul($s, $_1010);
$_10000 = self::sc25519_sq($_1000);
$_10110 = self::sc25519_sq($_1011);
$_100000 = self::sc25519_mul($_1010, $_10110);
$_100110 = self::sc25519_mul($_10000, $_10110);
$_1000000 = self::sc25519_sq($_100000);
$_1010000 = self::sc25519_mul($_10000, $_1000000);
$_1010011 = self::sc25519_mul($_11, $_1010000);
$_1100011 = self::sc25519_mul($_10000, $_1010011);
$_1100111 = self::sc25519_mul($_100, $_1100011);
$_1101011 = self::sc25519_mul($_100, $_1100111);
$_10010011 = self::sc25519_mul($_1000000, $_1010011);
$_10010111 = self::sc25519_mul($_100, $_10010011);
$_10111101 = self::sc25519_mul($_100110, $_10010111);
$_11010011 = self::sc25519_mul($_10110, $_10111101);
$_11100111 = self::sc25519_mul($_1010000, $_10010111);
$_11101011 = self::sc25519_mul($_100, $_11100111);
$_11110101 = self::sc25519_mul($_1010, $_11101011);
$recip = self::sc25519_mul($_1011, $_11110101);
$recip = self::sc25519_sqmul($recip, 126, $_1010011);
$recip = self::sc25519_sqmul($recip, 9, $_10);
$recip = self::sc25519_mul($recip, $_11110101);
$recip = self::sc25519_sqmul($recip, 7, $_1100111);
$recip = self::sc25519_sqmul($recip, 9, $_11110101);
$recip = self::sc25519_sqmul($recip, 11, $_10111101);
$recip = self::sc25519_sqmul($recip, 8, $_11100111);
$recip = self::sc25519_sqmul($recip, 9, $_1101011);
$recip = self::sc25519_sqmul($recip, 6, $_1011);
$recip = self::sc25519_sqmul($recip, 14, $_10010011);
$recip = self::sc25519_sqmul($recip, 10, $_1100011);
$recip = self::sc25519_sqmul($recip, 9, $_10010111);
$recip = self::sc25519_sqmul($recip, 10, $_11110101);
$recip = self::sc25519_sqmul($recip, 8, $_11010011);
return self::sc25519_sqmul($recip, 8, $_11101011);
}
/**
* @param string $s
* @return string
*/
public static function clamp($s)
{
$s_ = self::stringToIntArray($s);
$s_[0] &= 248;
$s_[31] |= 64;
$s_[31] &= 128;
return self::intArrayToString($s_);
}
/**
* Ensure limbs are less than 28 bits long to prevent float promotion.
*
* This uses a constant-time conditional swap under the hood.
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_normalize(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$x = (PHP_INT_SIZE << 3) - 1; // 31 or 63
$g = self::fe_copy($f);
for ($i = 0; $i < 10; ++$i) {
$mask = -(($g[$i] >> $x) & 1);
/*
* Get two candidate normalized values for $g[$i], depending on the sign of $g[$i]:
*/
$a = $g[$i] & 0x7ffffff;
$b = -((-$g[$i]) & 0x7ffffff);
/*
* Return the appropriate candidate value, based on the sign of the original input:
*
* The following is equivalent to this ternary:
*
* $g[$i] = (($g[$i] >> $x) & 1) ? $a : $b;
*
* Except what's written doesn't contain timing leaks.
*/
$g[$i] = ($a ^ (($a ^ $b) & $mask));
}
return $g;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_AEGIS_State256', false)) {
return;
}
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS_State256
{
/** @var array<int, string> $state */
protected $state;
public function __construct()
{
$this->state = array_fill(0, 6, '');
}
/**
* @internal Only use this for unit tests!
* @return string[]
*/
public function getState()
{
return array_values($this->state);
}
/**
* @param array $input
* @return self
* @throws SodiumException
*
* @internal Only for unit tests
*/
public static function initForUnitTests(array $input)
{
if (count($input) < 6) {
throw new SodiumException('invalid input');
}
$state = new self();
for ($i = 0; $i < 6; ++$i) {
$state->state[$i] = $input[$i];
}
return $state;
}
/**
* @param string $key
* @param string $nonce
* @return self
*/
public static function init($key, $nonce)
{
$state = new self();
$k0 = ParagonIE_Sodium_Core_Util::substr($key, 0, 16);
$k1 = ParagonIE_Sodium_Core_Util::substr($key, 16, 16);
$n0 = ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16);
$n1 = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16);
// S0 = k0 ^ n0
// S1 = k1 ^ n1
// S2 = C1
// S3 = C0
// S4 = k0 ^ C0
// S5 = k1 ^ C1
$k0_n0 = $k0 ^ $n0;
$k1_n1 = $k1 ^ $n1;
$state->state[0] = $k0_n0;
$state->state[1] = $k1_n1;
$state->state[2] = SODIUM_COMPAT_AEGIS_C1;
$state->state[3] = SODIUM_COMPAT_AEGIS_C0;
$state->state[4] = $k0 ^ SODIUM_COMPAT_AEGIS_C0;
$state->state[5] = $k1 ^ SODIUM_COMPAT_AEGIS_C1;
// Repeat(4,
// Update(k0)
// Update(k1)
// Update(k0 ^ n0)
// Update(k1 ^ n1)
// )
for ($i = 0; $i < 4; ++$i) {
$state->update($k0);
$state->update($k1);
$state->update($k0 ^ $n0);
$state->update($k1 ^ $n1);
}
return $state;
}
/**
* @param string $ai
* @return self
* @throws SodiumException
*/
public function absorb($ai)
{
if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) {
throw new SodiumException('Input must be an AES block in size');
}
return $this->update($ai);
}
/**
* @param string $ci
* @return string
* @throws SodiumException
*/
public function dec($ci)
{
if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) {
throw new SodiumException('Input must be an AES block in size');
}
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1]
^ $this->state[4]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
$xi = $ci ^ $z;
$this->update($xi);
return $xi;
}
/**
* @param string $cn
* @return string
*/
public function decPartial($cn)
{
$len = ParagonIE_Sodium_Core_Util::strlen($cn);
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1]
^ $this->state[4]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// t = ZeroPad(cn, 128)
$t = str_pad($cn, 16, "\0", STR_PAD_RIGHT);
// out = t ^ z
$out = $t ^ $z;
// xn = Truncate(out, |cn|)
$xn = ParagonIE_Sodium_Core_Util::substr($out, 0, $len);
// v = ZeroPad(xn, 128)
$v = str_pad($xn, 16, "\0", STR_PAD_RIGHT);
// Update(v)
$this->update($v);
// return xn
return $xn;
}
/**
* @param string $xi
* @return string
* @throws SodiumException
*/
public function enc($xi)
{
if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) {
throw new SodiumException('Input must be an AES block in size');
}
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1]
^ $this->state[4]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
$this->update($xi);
return $xi ^ $z;
}
/**
* @param int $ad_len_bits
* @param int $msg_len_bits
* @return string
*/
public function finalize($ad_len_bits, $msg_len_bits)
{
$encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
$t = $this->state[3] ^ $encoded;
for ($i = 0; $i < 7; ++$i) {
$this->update($t);
}
return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) .
($this->state[3] ^ $this->state[4] ^ $this->state[5]);
}
/**
* @param string $m
* @return self
*/
public function update($m)
{
/*
S'0 = AESRound(S5, S0 ^ M)
S'1 = AESRound(S0, S1)
S'2 = AESRound(S1, S2)
S'3 = AESRound(S2, S3)
S'4 = AESRound(S3, S4)
S'5 = AESRound(S4, S5)
*/
list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[5],$this->state[0] ^ $m,
$this->state[0], $this->state[1]
);
list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[1], $this->state[2],
$this->state[2], $this->state[3]
);
list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[3], $this->state[4],
$this->state[4], $this->state[5]
);
/*
S0 = S'0
S1 = S'1
S2 = S'2
S3 = S'3
S4 = S'4
S5 = S'5
*/
$this->state[0] = $s_0;
$this->state[1] = $s_1;
$this->state[2] = $s_2;
$this->state[3] = $s_3;
$this->state[4] = $s_4;
$this->state[5] = $s_5;
return $this;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_AEGIS_State128L', false)) {
return;
}
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS_State128L
{
/** @var array<int, string> $state */
protected $state;
public function __construct()
{
$this->state = array_fill(0, 8, '');
}
/**
* @internal Only use this for unit tests!
* @return string[]
*/
public function getState()
{
return array_values($this->state);
}
/**
* @param array $input
* @return self
* @throws SodiumException
*
* @internal Only for unit tests
*/
public static function initForUnitTests(array $input)
{
if (count($input) < 8) {
throw new SodiumException('invalid input');
}
$state = new self();
for ($i = 0; $i < 8; ++$i) {
$state->state[$i] = $input[$i];
}
return $state;
}
/**
* @param string $key
* @param string $nonce
* @return self
*/
public static function init($key, $nonce)
{
$state = new self();
// S0 = key ^ nonce
$state->state[0] = $key ^ $nonce;
// S1 = C1
$state->state[1] = SODIUM_COMPAT_AEGIS_C1;
// S2 = C0
$state->state[2] = SODIUM_COMPAT_AEGIS_C0;
// S3 = C1
$state->state[3] = SODIUM_COMPAT_AEGIS_C1;
// S4 = key ^ nonce
$state->state[4] = $key ^ $nonce;
// S5 = key ^ C0
$state->state[5] = $key ^ SODIUM_COMPAT_AEGIS_C0;
// S6 = key ^ C1
$state->state[6] = $key ^ SODIUM_COMPAT_AEGIS_C1;
// S7 = key ^ C0
$state->state[7] = $key ^ SODIUM_COMPAT_AEGIS_C0;
// Repeat(10, Update(nonce, key))
for ($i = 0; $i < 10; ++$i) {
$state->update($nonce, $key);
}
return $state;
}
/**
* @param string $ai
* @return self
*/
public function absorb($ai)
{
if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) {
throw new SodiumException('Input must be two AES blocks in size');
}
$t0 = ParagonIE_Sodium_Core_Util::substr($ai, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($ai, 16, 16);
return $this->update($t0, $t1);
}
/**
* @param string $ci
* @return string
* @throws SodiumException
*/
public function dec($ci)
{
if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) {
throw new SodiumException('Input must be two AES blocks in size');
}
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6]
^ $this->state[1]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(xi, 128)
$t0 = ParagonIE_Sodium_Core_Util::substr($ci, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($ci, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// Update(out0, out1)
// xi = out0 || out1
$this->update($out0, $out1);
return $out0 . $out1;
}
/**
* @param string $cn
* @return string
*/
public function decPartial($cn)
{
$len = ParagonIE_Sodium_Core_Util::strlen($cn);
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6]
^ $this->state[1]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(ZeroPad(cn, 256), 128)
$cn = str_pad($cn, 32, "\0", STR_PAD_RIGHT);
$t0 = ParagonIE_Sodium_Core_Util::substr($cn, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($cn, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// xn = Truncate(out0 || out1, |cn|)
$xn = ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len);
// v0, v1 = Split(ZeroPad(xn, 256), 128)
$padded = str_pad($xn, 32, "\0", STR_PAD_RIGHT);
$v0 = ParagonIE_Sodium_Core_Util::substr($padded, 0, 16);
$v1 = ParagonIE_Sodium_Core_Util::substr($padded, 16, 16);
// Update(v0, v1)
$this->update($v0, $v1);
// return xn
return $xn;
}
/**
* @param string $xi
* @return string
* @throws SodiumException
*/
public function enc($xi)
{
if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) {
throw new SodiumException('Input must be two AES blocks in size');
}
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6]
^ $this->state[1]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(xi, 128)
$t0 = ParagonIE_Sodium_Core_Util::substr($xi, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($xi, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// Update(t0, t1)
// ci = out0 || out1
$this->update($t0, $t1);
// return ci
return $out0 . $out1;
}
/**
* @param int $ad_len_bits
* @param int $msg_len_bits
* @return string
*/
public function finalize($ad_len_bits, $msg_len_bits)
{
$encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
$t = $this->state[2] ^ $encoded;
for ($i = 0; $i < 7; ++$i) {
$this->update($t, $t);
}
return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) .
($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]);
}
/**
* @param string $m0
* @param string $m1
* @return self
*/
public function update($m0, $m1)
{
/*
S'0 = AESRound(S7, S0 ^ M0)
S'1 = AESRound(S0, S1)
S'2 = AESRound(S1, S2)
S'3 = AESRound(S2, S3)
S'4 = AESRound(S3, S4 ^ M1)
S'5 = AESRound(S4, S5)
S'6 = AESRound(S5, S6)
S'7 = AESRound(S6, S7)
*/
list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[7], $this->state[0] ^ $m0,
$this->state[0], $this->state[1]
);
list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[1], $this->state[2],
$this->state[2], $this->state[3]
);
list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[3], $this->state[4] ^ $m1,
$this->state[4], $this->state[5]
);
list($s_6, $s_7) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[5], $this->state[6],
$this->state[6], $this->state[7]
);
/*
S0 = S'0
S1 = S'1
S2 = S'2
S3 = S'3
S4 = S'4
S5 = S'5
S6 = S'6
S7 = S'7
*/
$this->state[0] = $s_0;
$this->state[1] = $s_1;
$this->state[2] = $s_2;
$this->state[3] = $s_3;
$this->state[4] = $s_4;
$this->state[5] = $s_5;
$this->state[6] = $s_6;
$this->state[7] = $s_7;
return $this;
}
}<?php
if (class_exists('ParagonIE_Sodium_Core_XChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XChaCha20
*/
class ParagonIE_Sodium_Core_XChaCha20 extends ParagonIE_Sodium_Core_HChaCha20
{
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len = 64, $nonce = '', $key = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
self::substr($nonce, 16, 8),
$ic
),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8),
$ic
),
$message
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_AES_Block', false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray
{
/**
* @var array<int, int>
*/
protected $values = array();
/**
* @var int
*/
protected $size;
/**
* @param int $size
*/
public function __construct($size = 8)
{
parent::__construct($size);
$this->size = $size;
$this->values = array_fill(0, $size, 0);
}
/**
* @return self
*/
public static function init()
{
return new self(8);
}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
*
* @psalm-suppress MethodSignatureMismatch
*/
#[ReturnTypeWillChange]
public static function fromArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
/** @var array<int, int> $keys */
$obj = new ParagonIE_Sodium_Core_AES_Block();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!is_int($value)) {
throw new InvalidArgumentException('Expected an integer');
}
if (is_null($offset)) {
$this->values[] = $value;
} else {
$this->values[$offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->values[$offset])) {
$this->values[$offset] = 0;
}
return (int) ($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
$out = array();
foreach ($this->values as $v) {
$out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT);
}
return array(implode(', ', $out));
/*
return array(implode(', ', $this->values));
*/
}
/**
* @param int $cl low bit mask
* @param int $ch high bit mask
* @param int $s shift
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swapN($cl, $ch, $s, $x, $y)
{
static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX;
$a = $this->values[$x] & $u32mask;
$b = $this->values[$y] & $u32mask;
// (x) = (a & cl) | ((b & cl) << (s));
$this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask);
// (y) = ((a & ch) >> (s)) | (b & ch);
$this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch);
return $this;
}
/**
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swap2($x, $y)
{
return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y);
}
/**
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swap4($x, $y)
{
return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y);
}
/**
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swap8($x, $y)
{
return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y);
}
/**
* @return self
*/
public function orthogonalize()
{
return $this
->swap2(0, 1)
->swap2(2, 3)
->swap2(4, 5)
->swap2(6, 7)
->swap4(0, 2)
->swap4(1, 3)
->swap4(4, 6)
->swap4(5, 7)
->swap8(0, 4)
->swap8(1, 5)
->swap8(2, 6)
->swap8(3, 7);
}
/**
* @return self
*/
public function shiftRows()
{
for ($i = 0; $i < 8; ++$i) {
$x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[$i] = (
($x & 0x000000FF)
| (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6)
| (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4)
| (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2)
) & ParagonIE_Sodium_Core_Util::U32_MAX;
}
return $this;
}
/**
* @param int $x
* @return int
*/
public static function rotr16($x)
{
return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16);
}
/**
* @return self
*/
public function mixColumns()
{
$q0 = $this->values[0];
$q1 = $this->values[1];
$q2 = $this->values[2];
$q3 = $this->values[3];
$q4 = $this->values[4];
$q5 = $this->values[5];
$q6 = $this->values[6];
$q7 = $this->values[7];
$r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0);
$this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1);
$this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2);
$this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3);
$this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4);
$this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5);
$this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6);
$this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7);
return $this;
}
/**
* @return self
*/
public function inverseMixColumns()
{
$q0 = $this->values[0];
$q1 = $this->values[1];
$q2 = $this->values[2];
$q3 = $this->values[3];
$q4 = $this->values[4];
$q5 = $this->values[5];
$q6 = $this->values[6];
$q7 = $this->values[7];
$r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5);
$this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6);
$this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7);
$this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7);
$this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6);
$this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7);
$this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7);
$this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7);
return $this;
}
/**
* @return self
*/
public function inverseShiftRows()
{
for ($i = 0; $i < 8; ++$i) {
$x = $this->values[$i];
$this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & (
($x & 0x000000FF)
| (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6)
| (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4)
| (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2)
);
}
return $this;
}
}
[02-Dec-2025 10:42:55 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_AES_KeySchedule" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AES/Expanded.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/AES/Expanded.php on line 10
<?php
if (class_exists('ParagonIE_Sodium_Core_AES_Expanded', false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_Expanded extends ParagonIE_Sodium_Core_AES_KeySchedule
{
/** @var bool $expanded */
protected $expanded = true;
}
<?php
if (class_exists('ParagonIE_Sodium_Core_AES_KeySchedule', false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_KeySchedule
{
/** @var array<int, int> $skey -- has size 120 */
protected $skey;
/** @var bool $expanded */
protected $expanded = false;
/** @var int $numRounds */
private $numRounds;
/**
* @param array $skey
* @param int $numRounds
*/
public function __construct(array $skey, $numRounds = 10)
{
$this->skey = $skey;
$this->numRounds = $numRounds;
}
/**
* Get a value at an arbitrary index. Mostly used for unit testing.
*
* @param int $i
* @return int
*/
public function get($i)
{
return $this->skey[$i];
}
/**
* @return int
*/
public function getNumRounds()
{
return $this->numRounds;
}
/**
* @param int $offset
* @return ParagonIE_Sodium_Core_AES_Block
*/
public function getRoundKey($offset)
{
return ParagonIE_Sodium_Core_AES_Block::fromArray(
array_slice($this->skey, $offset, 8)
);
}
/**
* Return an expanded key schedule
*
* @return ParagonIE_Sodium_Core_AES_Expanded
*/
public function expand()
{
$exp = new ParagonIE_Sodium_Core_AES_Expanded(
array_fill(0, 120, 0),
$this->numRounds
);
$n = ($exp->numRounds + 1) << 2;
for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) {
$x = $y = $this->skey[$u];
$x &= 0x55555555;
$exp->skey[$v] = ($x | ($x << 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$y &= 0xAAAAAAAA;
$exp->skey[$v + 1] = ($y | ($y >> 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
}
return $exp;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_HSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HSalsa20
*/
abstract class ParagonIE_Sodium_Core_HSalsa20 extends ParagonIE_Sodium_Core_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hsalsa20($in, $k, $c = null)
{
if ($c === null) {
$x0 = 0x61707865;
$x5 = 0x3320646e;
$x10 = 0x79622d32;
$x15 = 0x6b206574;
} else {
$x0 = self::load_4(self::substr($c, 0, 4));
$x5 = self::load_4(self::substr($c, 4, 4));
$x10 = self::load_4(self::substr($c, 8, 4));
$x15 = self::load_4(self::substr($c, 12, 4));
}
$x1 = self::load_4(self::substr($k, 0, 4));
$x2 = self::load_4(self::substr($k, 4, 4));
$x3 = self::load_4(self::substr($k, 8, 4));
$x4 = self::load_4(self::substr($k, 12, 4));
$x11 = self::load_4(self::substr($k, 16, 4));
$x12 = self::load_4(self::substr($k, 20, 4));
$x13 = self::load_4(self::substr($k, 24, 4));
$x14 = self::load_4(self::substr($k, 28, 4));
$x6 = self::load_4(self::substr($in, 0, 4));
$x7 = self::load_4(self::substr($in, 4, 4));
$x8 = self::load_4(self::substr($in, 8, 4));
$x9 = self::load_4(self::substr($in, 12, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
return self::store32_le($x0) .
self::store32_le($x5) .
self::store32_le($x10) .
self::store32_le($x15) .
self::store32_le($x6) .
self::store32_le($x7) .
self::store32_le($x8) .
self::store32_le($x9);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20
*/
class ParagonIE_Sodium_Core_ChaCha20 extends ParagonIE_Sodium_Core_Util
{
/**
* Bitwise left rotation
*
* @internal You should not use this directly from another application
*
* @param int $v
* @param int $n
* @return int
*/
public static function rotate($v, $n)
{
$v &= 0xffffffff;
$n &= 31;
return (int) (
0xffffffff & (
($v << $n)
|
($v >> (32 - $n))
)
);
}
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @return array<int, int>
*/
protected static function quarterRound($a, $b, $c, $d)
{
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
/** @var int $a */
$a = ($a + $b) & 0xffffffff;
$d = self::rotate($d ^ $a, 16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
/** @var int $c */
$c = ($c + $d) & 0xffffffff;
$b = self::rotate($b ^ $c, 12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
/** @var int $a */
$a = ($a + $b) & 0xffffffff;
$d = self::rotate($d ^ $a, 8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
/** @var int $c */
$c = ($c + $d) & 0xffffffff;
$b = self::rotate($b ^ $c, 7);
return array((int) $a, (int) $b, (int) $c, (int) $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws TypeError
* @throws SodiumException
*/
public static function encryptBytes(
ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx,
$message = ''
) {
$bytes = self::strlen($message);
/*
j0 = ctx->input[0];
j1 = ctx->input[1];
j2 = ctx->input[2];
j3 = ctx->input[3];
j4 = ctx->input[4];
j5 = ctx->input[5];
j6 = ctx->input[6];
j7 = ctx->input[7];
j8 = ctx->input[8];
j9 = ctx->input[9];
j10 = ctx->input[10];
j11 = ctx->input[11];
j12 = ctx->input[12];
j13 = ctx->input[13];
j14 = ctx->input[14];
j15 = ctx->input[15];
*/
$j0 = (int) $ctx[0];
$j1 = (int) $ctx[1];
$j2 = (int) $ctx[2];
$j3 = (int) $ctx[3];
$j4 = (int) $ctx[4];
$j5 = (int) $ctx[5];
$j6 = (int) $ctx[6];
$j7 = (int) $ctx[7];
$j8 = (int) $ctx[8];
$j9 = (int) $ctx[9];
$j10 = (int) $ctx[10];
$j11 = (int) $ctx[11];
$j12 = (int) $ctx[12];
$j13 = (int) $ctx[13];
$j14 = (int) $ctx[14];
$j15 = (int) $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= str_repeat("\x00", 64 - $bytes);
}
$x0 = (int) $j0;
$x1 = (int) $j1;
$x2 = (int) $j2;
$x3 = (int) $j3;
$x4 = (int) $j4;
$x5 = (int) $j5;
$x6 = (int) $j6;
$x7 = (int) $j7;
$x8 = (int) $j8;
$x9 = (int) $j9;
$x10 = (int) $j10;
$x11 = (int) $j11;
$x12 = (int) $j12;
$x13 = (int) $j13;
$x14 = (int) $j14;
$x15 = (int) $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
/*
x0 = PLUS(x0, j0);
x1 = PLUS(x1, j1);
x2 = PLUS(x2, j2);
x3 = PLUS(x3, j3);
x4 = PLUS(x4, j4);
x5 = PLUS(x5, j5);
x6 = PLUS(x6, j6);
x7 = PLUS(x7, j7);
x8 = PLUS(x8, j8);
x9 = PLUS(x9, j9);
x10 = PLUS(x10, j10);
x11 = PLUS(x11, j11);
x12 = PLUS(x12, j12);
x13 = PLUS(x13, j13);
x14 = PLUS(x14, j14);
x15 = PLUS(x15, j15);
*/
/** @var int $x0 */
$x0 = ($x0 & 0xffffffff) + $j0;
/** @var int $x1 */
$x1 = ($x1 & 0xffffffff) + $j1;
/** @var int $x2 */
$x2 = ($x2 & 0xffffffff) + $j2;
/** @var int $x3 */
$x3 = ($x3 & 0xffffffff) + $j3;
/** @var int $x4 */
$x4 = ($x4 & 0xffffffff) + $j4;
/** @var int $x5 */
$x5 = ($x5 & 0xffffffff) + $j5;
/** @var int $x6 */
$x6 = ($x6 & 0xffffffff) + $j6;
/** @var int $x7 */
$x7 = ($x7 & 0xffffffff) + $j7;
/** @var int $x8 */
$x8 = ($x8 & 0xffffffff) + $j8;
/** @var int $x9 */
$x9 = ($x9 & 0xffffffff) + $j9;
/** @var int $x10 */
$x10 = ($x10 & 0xffffffff) + $j10;
/** @var int $x11 */
$x11 = ($x11 & 0xffffffff) + $j11;
/** @var int $x12 */
$x12 = ($x12 & 0xffffffff) + $j12;
/** @var int $x13 */
$x13 = ($x13 & 0xffffffff) + $j13;
/** @var int $x14 */
$x14 = ($x14 & 0xffffffff) + $j14;
/** @var int $x15 */
$x15 = ($x15 & 0xffffffff) + $j15;
/*
x0 = XOR(x0, LOAD32_LE(m + 0));
x1 = XOR(x1, LOAD32_LE(m + 4));
x2 = XOR(x2, LOAD32_LE(m + 8));
x3 = XOR(x3, LOAD32_LE(m + 12));
x4 = XOR(x4, LOAD32_LE(m + 16));
x5 = XOR(x5, LOAD32_LE(m + 20));
x6 = XOR(x6, LOAD32_LE(m + 24));
x7 = XOR(x7, LOAD32_LE(m + 28));
x8 = XOR(x8, LOAD32_LE(m + 32));
x9 = XOR(x9, LOAD32_LE(m + 36));
x10 = XOR(x10, LOAD32_LE(m + 40));
x11 = XOR(x11, LOAD32_LE(m + 44));
x12 = XOR(x12, LOAD32_LE(m + 48));
x13 = XOR(x13, LOAD32_LE(m + 52));
x14 = XOR(x14, LOAD32_LE(m + 56));
x15 = XOR(x15, LOAD32_LE(m + 60));
*/
$x0 ^= self::load_4(self::substr($message, 0, 4));
$x1 ^= self::load_4(self::substr($message, 4, 4));
$x2 ^= self::load_4(self::substr($message, 8, 4));
$x3 ^= self::load_4(self::substr($message, 12, 4));
$x4 ^= self::load_4(self::substr($message, 16, 4));
$x5 ^= self::load_4(self::substr($message, 20, 4));
$x6 ^= self::load_4(self::substr($message, 24, 4));
$x7 ^= self::load_4(self::substr($message, 28, 4));
$x8 ^= self::load_4(self::substr($message, 32, 4));
$x9 ^= self::load_4(self::substr($message, 36, 4));
$x10 ^= self::load_4(self::substr($message, 40, 4));
$x11 ^= self::load_4(self::substr($message, 44, 4));
$x12 ^= self::load_4(self::substr($message, 48, 4));
$x13 ^= self::load_4(self::substr($message, 52, 4));
$x14 ^= self::load_4(self::substr($message, 56, 4));
$x15 ^= self::load_4(self::substr($message, 60, 4));
/*
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
}
*/
++$j12;
if ($j12 & 0xf0000000) {
throw new SodiumException('Overflow');
}
/*
STORE32_LE(c + 0, x0);
STORE32_LE(c + 4, x1);
STORE32_LE(c + 8, x2);
STORE32_LE(c + 12, x3);
STORE32_LE(c + 16, x4);
STORE32_LE(c + 20, x5);
STORE32_LE(c + 24, x6);
STORE32_LE(c + 28, x7);
STORE32_LE(c + 32, x8);
STORE32_LE(c + 36, x9);
STORE32_LE(c + 40, x10);
STORE32_LE(c + 44, x11);
STORE32_LE(c + 48, x12);
STORE32_LE(c + 52, x13);
STORE32_LE(c + 56, x14);
STORE32_LE(c + 60, x15);
*/
$block = self::store32_le((int) ($x0 & 0xffffffff)) .
self::store32_le((int) ($x1 & 0xffffffff)) .
self::store32_le((int) ($x2 & 0xffffffff)) .
self::store32_le((int) ($x3 & 0xffffffff)) .
self::store32_le((int) ($x4 & 0xffffffff)) .
self::store32_le((int) ($x5 & 0xffffffff)) .
self::store32_le((int) ($x6 & 0xffffffff)) .
self::store32_le((int) ($x7 & 0xffffffff)) .
self::store32_le((int) ($x8 & 0xffffffff)) .
self::store32_le((int) ($x9 & 0xffffffff)) .
self::store32_le((int) ($x10 & 0xffffffff)) .
self::store32_le((int) ($x11 & 0xffffffff)) .
self::store32_le((int) ($x12 & 0xffffffff)) .
self::store32_le((int) ($x13 & 0xffffffff)) .
self::store32_le((int) ($x14 & 0xffffffff)) .
self::store32_le((int) ($x15 & 0xffffffff));
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len, $nonce = '', $key = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic),
$message
);
}
}
[02-Dec-2025 10:42:58 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Poly1305/State.php:10
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/src/Core/Poly1305/State.php on line 10
<?php
if (class_exists('ParagonIE_Sodium_Core_Poly1305_State', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305_State
*/
class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = false;
/**
* @var array<int, int>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var int[]
*/
public $r;
/**
* @var int[]
*/
public $pad;
/**
* ParagonIE_Sodium_Core_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Poly1305 requires a 32-byte key'
);
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
(int) ((self::load_4(self::substr($key, 0, 4))) & 0x3ffffff),
(int) ((self::load_4(self::substr($key, 3, 4)) >> 2) & 0x3ffff03),
(int) ((self::load_4(self::substr($key, 6, 4)) >> 4) & 0x3ffc0ff),
(int) ((self::load_4(self::substr($key, 9, 4)) >> 6) & 0x3f03fff),
(int) ((self::load_4(self::substr($key, 12, 4)) >> 8) & 0x00fffff)
);
/* h = 0 */
$this->h = array(0, 0, 0, 0, 0);
/* save pad for later */
$this->pad = array(
self::load_4(self::substr($key, 16, 4)),
self::load_4(self::substr($key, 20, 4)),
self::load_4(self::substr($key, 24, 4)),
self::load_4(self::substr($key, 28, 4)),
);
$this->leftover = 0;
$this->final = false;
}
/**
* Zero internal buffer upon destruction
*/
public function __destruct()
{
$this->r[0] ^= $this->r[0];
$this->r[1] ^= $this->r[1];
$this->r[2] ^= $this->r[2];
$this->r[3] ^= $this->r[3];
$this->r[4] ^= $this->r[4];
$this->h[0] ^= $this->h[0];
$this->h[1] ^= $this->h[1];
$this->h[2] ^= $this->h[2];
$this->h[3] ^= $this->h[3];
$this->h[4] ^= $this->h[4];
$this->pad[0] ^= $this->pad[0];
$this->pad[1] ^= $this->pad[1];
$this->pad[2] ^= $this->pad[2];
$this->pad[3] ^= $this->pad[3];
$this->leftover = 0;
$this->final = true;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
if ($bytes < 1) {
return $this;
}
/* handle leftover */
if ($this->leftover) {
$want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run $this->blocks()
return $this;
}
$this->blocks(
self::intArrayToString($this->buffer),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes & ~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1);
if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$block = self::substr($message, 0, $want);
if (self::strlen($block) >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = str_pad($message, 16, "\x00", STR_PAD_RIGHT);
}
/** @var int $hibit */
$hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */
$r0 = (int) $this->r[0];
$r1 = (int) $this->r[1];
$r2 = (int) $this->r[2];
$r3 = (int) $this->r[3];
$r4 = (int) $this->r[4];
$s1 = self::mul($r1, 5, 3);
$s2 = self::mul($r2, 5, 3);
$s3 = self::mul($r3, 5, 3);
$s4 = self::mul($r4, 5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff;
$h1 += (self::load_4(self::substr($message, 3, 4)) >> 2) & 0x3ffffff;
$h2 += (self::load_4(self::substr($message, 6, 4)) >> 4) & 0x3ffffff;
$h3 += (self::load_4(self::substr($message, 9, 4)) >> 6) & 0x3ffffff;
$h4 += (self::load_4(self::substr($message, 12, 4)) >> 8) | $hibit;
/* h *= r */
$d0 = (
self::mul($h0, $r0, 27) +
self::mul($s4, $h1, 27) +
self::mul($s3, $h2, 27) +
self::mul($s2, $h3, 27) +
self::mul($s1, $h4, 27)
);
$d1 = (
self::mul($h0, $r1, 27) +
self::mul($h1, $r0, 27) +
self::mul($s4, $h2, 27) +
self::mul($s3, $h3, 27) +
self::mul($s2, $h4, 27)
);
$d2 = (
self::mul($h0, $r2, 27) +
self::mul($h1, $r1, 27) +
self::mul($h2, $r0, 27) +
self::mul($s4, $h3, 27) +
self::mul($s3, $h4, 27)
);
$d3 = (
self::mul($h0, $r3, 27) +
self::mul($h1, $r2, 27) +
self::mul($h2, $r1, 27) +
self::mul($h3, $r0, 27) +
self::mul($s4, $h4, 27)
);
$d4 = (
self::mul($h0, $r4, 27) +
self::mul($h1, $r3, 27) +
self::mul($h2, $r2, 27) +
self::mul($h3, $r1, 27) +
self::mul($h4, $r0, 27)
);
/* (partial) h %= p */
/** @var int $c */
$c = $d0 >> 26;
/** @var int $h0 */
$h0 = $d0 & 0x3ffffff;
$d1 += $c;
/** @var int $c */
$c = $d1 >> 26;
/** @var int $h1 */
$h1 = $d1 & 0x3ffffff;
$d2 += $c;
/** @var int $c */
$c = $d2 >> 26;
/** @var int $h2 */
$h2 = $d2 & 0x3ffffff;
$d3 += $c;
/** @var int $c */
$c = $d3 >> 26;
/** @var int $h3 */
$h3 = $d3 & 0x3ffffff;
$d4 += $c;
/** @var int $c */
$c = $d4 >> 26;
/** @var int $h4 */
$h4 = $d4 & 0x3ffffff;
$h0 += (int) self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
$h1 += $c;
// Chop off the left 32 bytes.
$message = self::substr(
$message,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE;
}
$this->h = array(
(int) ($h0 & 0xffffffff),
(int) ($h1 & 0xffffffff),
(int) ($h2 & 0xffffffff),
(int) ($h3 & 0xffffffff),
(int) ($h4 & 0xffffffff)
);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) {
$this->buffer[$i] = 0;
}
$this->final = true;
$this->blocks(
self::substr(
self::intArrayToString($this->buffer),
0,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
}
$h0 = (int) $this->h[0];
$h1 = (int) $this->h[1];
$h2 = (int) $this->h[2];
$h3 = (int) $this->h[3];
$h4 = (int) $this->h[4];
/** @var int $c */
$c = $h1 >> 26;
/** @var int $h1 */
$h1 &= 0x3ffffff;
/** @var int $h2 */
$h2 += $c;
/** @var int $c */
$c = $h2 >> 26;
/** @var int $h2 */
$h2 &= 0x3ffffff;
$h3 += $c;
/** @var int $c */
$c = $h3 >> 26;
$h3 &= 0x3ffffff;
$h4 += $c;
/** @var int $c */
$c = $h4 >> 26;
$h4 &= 0x3ffffff;
/** @var int $h0 */
$h0 += self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
/** @var int $h1 */
$h1 += $c;
/* compute h + -p */
/** @var int $g0 */
$g0 = $h0 + 5;
/** @var int $c */
$c = $g0 >> 26;
/** @var int $g0 */
$g0 &= 0x3ffffff;
/** @var int $g1 */
$g1 = $h1 + $c;
/** @var int $c */
$c = $g1 >> 26;
$g1 &= 0x3ffffff;
/** @var int $g2 */
$g2 = $h2 + $c;
/** @var int $c */
$c = $g2 >> 26;
/** @var int $g2 */
$g2 &= 0x3ffffff;
/** @var int $g3 */
$g3 = $h3 + $c;
/** @var int $c */
$c = $g3 >> 26;
/** @var int $g3 */
$g3 &= 0x3ffffff;
/** @var int $g4 */
$g4 = ($h4 + $c - (1 << 26)) & 0xffffffff;
/* select h if h < p, or h + -p if h >= p */
/** @var int $mask */
$mask = ($g4 >> 31) - 1;
$g0 &= $mask;
$g1 &= $mask;
$g2 &= $mask;
$g3 &= $mask;
$g4 &= $mask;
/** @var int $mask */
$mask = ~$mask & 0xffffffff;
/** @var int $h0 */
$h0 = ($h0 & $mask) | $g0;
/** @var int $h1 */
$h1 = ($h1 & $mask) | $g1;
/** @var int $h2 */
$h2 = ($h2 & $mask) | $g2;
/** @var int $h3 */
$h3 = ($h3 & $mask) | $g3;
/** @var int $h4 */
$h4 = ($h4 & $mask) | $g4;
/* h = h % (2^128) */
/** @var int $h0 */
$h0 = (($h0) | ($h1 << 26)) & 0xffffffff;
/** @var int $h1 */
$h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff;
/** @var int $h2 */
$h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff;
/** @var int $h3 */
$h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
$f = (int) ($h0 + $this->pad[0]);
$h0 = (int) $f;
$f = (int) ($h1 + $this->pad[1] + ($f >> 32));
$h1 = (int) $f;
$f = (int) ($h2 + $this->pad[2] + ($f >> 32));
$h2 = (int) $f;
$f = (int) ($h3 + $this->pad[3] + ($f >> 32));
$h3 = (int) $f;
return self::store32_le($h0 & 0xffffffff) .
self::store32_le($h1 & 0xffffffff) .
self::store32_le($h2 & 0xffffffff) .
self::store32_le($h3 & 0xffffffff);
}
}
<?php
/**
* Class ParagonIE_Sodium_Core_Base64UrlSafe
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*/
class ParagonIE_Sodium_Core_Base64_UrlSafe
{
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = true)
{
$dest = '';
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .=
self::encode6Bits( $b0 >> 2 ) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
self::encode6Bits( $b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
self::encode6Bits($b0 >> 2) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
self::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
self::encode6Bits( $b0 >> 2) .
self::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = false)
{
// Remove padding
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new RangeException(
'Incorrect padding'
);
}
if ($src[$srcLen - 1] === '=') {
throw new RangeException(
'Incorrect padding'
);
}
} else {
$src = rtrim($src, '=');
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= pack(
'CCC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff),
((($c2 << 6) | $c3) & 0xff)
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff)
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the correct base64 alphabet'
);
}
return $dest;
}
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
// if ($src == 0x2c) $ret += 62 + 1;
$ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;
// if ($src == 0x5f) ret += 63 + 1;
$ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += ((25 - $src) >> 8) & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= ((51 - $src) >> 8) & 75;
// if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
$diff -= ((61 - $src) >> 8) & 13;
// if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
$diff += ((62 - $src) >> 8) & 49;
return pack('C', $src + $diff);
}
}
<?php<?php
/**
* Class ParagonIE_Sodium_Core_Base64
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*/
class ParagonIE_Sodium_Core_Base64_Original
{
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = true)
{
$dest = '';
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .=
self::encode6Bits( $b0 >> 2 ) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
self::encode6Bits( $b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
self::encode6Bits($b0 >> 2) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
self::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
self::encode6Bits( $b0 >> 2) .
self::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = false)
{
// Remove padding
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new RangeException(
'Incorrect padding'
);
}
if ($src[$srcLen - 1] === '=') {
throw new RangeException(
'Incorrect padding'
);
}
} else {
$src = rtrim($src, '=');
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= pack(
'CCC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff),
((($c2 << 6) | $c3) & 0xff)
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff)
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the correct base64 alphabet'
);
}
return $dest;
}
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
// if ($src == 0x2b) $ret += 62 + 1;
$ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63;
// if ($src == 0x2f) ret += 63 + 1;
$ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += ((25 - $src) >> 8) & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= ((51 - $src) >> 8) & 75;
// if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
$diff -= ((61 - $src) >> 8) & 15;
// if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
$diff += ((62 - $src) >> 8) & 3;
return pack('C', $src + $diff);
}
}
<?php
if (class_exists('SplFixedArray')) {
return;
}
/**
* The SplFixedArray class provides the main functionalities of array. The
* main differences between a SplFixedArray and a normal PHP array is that
* the SplFixedArray is of fixed length and allows only integers within
* the range as indexes. The advantage is that it allows a faster array
* implementation.
*/
class SplFixedArray implements Iterator, ArrayAccess, Countable
{
/** @var array<int, mixed> */
private $internalArray = array();
/** @var int $size */
private $size = 0;
/**
* SplFixedArray constructor.
* @param int $size
*/
public function __construct($size = 0)
{
$this->size = $size;
$this->internalArray = array();
}
/**
* @return int
*/
public function count()
{
return count($this->internalArray);
}
/**
* @return array
*/
public function toArray()
{
ksort($this->internalArray);
return (array) $this->internalArray;
}
/**
* @param array $array
* @param bool $save_indexes
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function fromArray(array $array, $save_indexes = true)
{
$self = new SplFixedArray(count($array));
if($save_indexes) {
foreach($array as $key => $value) {
$self[(int) $key] = $value;
}
} else {
$i = 0;
foreach (array_values($array) as $value) {
$self[$i] = $value;
$i++;
}
}
return $self;
}
/**
* @return int
*/
public function getSize()
{
return $this->size;
}
/**
* @param int $size
* @return bool
*/
public function setSize($size)
{
$this->size = $size;
return true;
}
/**
* @param string|int $index
* @return bool
*/
public function offsetExists($index)
{
return array_key_exists((int) $index, $this->internalArray);
}
/**
* @param string|int $index
* @return mixed
*/
public function offsetGet($index)
{
/** @psalm-suppress MixedReturnStatement */
return $this->internalArray[(int) $index];
}
/**
* @param string|int $index
* @param mixed $newval
* @psalm-suppress MixedAssignment
*/
public function offsetSet($index, $newval)
{
$this->internalArray[(int) $index] = $newval;
}
/**
* @param string|int $index
*/
public function offsetUnset($index)
{
unset($this->internalArray[(int) $index]);
}
/**
* Rewind iterator back to the start
* @link https://php.net/manual/en/splfixedarray.rewind.php
* @return void
* @since 5.3.0
*/
public function rewind()
{
reset($this->internalArray);
}
/**
* Return current array entry
* @link https://php.net/manual/en/splfixedarray.current.php
* @return mixed The current element value.
* @since 5.3.0
*/
public function current()
{
/** @psalm-suppress MixedReturnStatement */
return current($this->internalArray);
}
/**
* Return current array index
* @return int The current array index.
*/
public function key()
{
return key($this->internalArray);
}
/**
* @return void
*/
public function next()
{
next($this->internalArray);
}
/**
* Check whether the array contains more elements
* @link https://php.net/manual/en/splfixedarray.valid.php
* @return bool true if the array contains any more elements, false otherwise.
*/
public function valid()
{
if (empty($this->internalArray)) {
return false;
}
$result = next($this->internalArray) !== false;
prev($this->internalArray);
return $result;
}
/**
* Do nothing.
*/
public function __wakeup()
{
// NOP
}
}<?php
if (class_exists('ParagonIE_Sodium_Crypto', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Crypto
*
* ATTENTION!
*
* If you are using this library, you should be using
* ParagonIE_Sodium_Compat in your code, not this class.
*/
abstract class ParagonIE_Sodium_Crypto
{
const aead_chacha20poly1305_KEYBYTES = 32;
const aead_chacha20poly1305_NSECBYTES = 0;
const aead_chacha20poly1305_NPUBBYTES = 8;
const aead_chacha20poly1305_ABYTES = 16;
const aead_chacha20poly1305_IETF_KEYBYTES = 32;
const aead_chacha20poly1305_IETF_NSECBYTES = 0;
const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
const aead_chacha20poly1305_IETF_ABYTES = 16;
const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
const aead_xchacha20poly1305_IETF_ABYTES = 16;
const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
const box_curve25519xsalsa20poly1305_MACBYTES = 16;
const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
const onetimeauth_poly1305_BYTES = 16;
const onetimeauth_poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
const secretbox_xsalsa20poly1305_MACBYTES = 16;
const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
const secretbox_xchacha20poly1305_KEYBYTES = 32;
const secretbox_xchacha20poly1305_NONCEBYTES = 24;
const secretbox_xchacha20poly1305_MACBYTES = 16;
const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
const secretbox_xchacha20poly1305_ZEROBYTES = 32;
const stream_salsa20_KEYBYTES = 32;
/**
* AEAD Decryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_ABYTES;
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core_Util::substr(
$message,
$clen,
self::aead_chacha20poly1305_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 0, $clen);
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
32,
$nonce,
$key
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return the plaintext
return ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
$state->update($ad);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
32,
$nonce,
$key
);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core_Util::substr(
$message,
$len - self::aead_chacha20poly1305_IETF_ABYTES,
self::aead_chacha20poly1305_IETF_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core_Util::substr(
$message,
0,
$len - self::aead_chacha20poly1305_IETF_ABYTES
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", (0x10 - $clen) & 0xf));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return the plaintext
return ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", ((0x10 - $len) & 0xf)));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey);
}
/**
* HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $key
* @return string
* @throws TypeError
*/
public static function auth($message, $key)
{
return ParagonIE_Sodium_Core_Util::substr(
hash_hmac('sha512', $message, $key, true),
0,
32
);
}
/**
* HMAC-SHA-512-256 validation. Constant-time via hash_equals().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function auth_verify($mac, $message, $key)
{
return ParagonIE_Sodium_Core_Util::hashEquals(
$mac,
self::auth($message, $key)
);
}
/**
* X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box($plaintext, $nonce, $keypair)
{
$c = self::secretbox(
$plaintext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
return $c;
}
/**
* X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal($message, $publicKey)
{
/** @var string $ephemeralKeypair */
$ephemeralKeypair = self::box_keypair();
/** @var string $ephemeralSK */
$ephemeralSK = self::box_secretkey($ephemeralKeypair);
/** @var string $ephemeralPK */
$ephemeralPK = self::box_publickey($ephemeralKeypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair - The combined keypair used in crypto_box() */
$keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
/** @var string $ciphertext Ciphertext + MAC from crypto_box */
$ciphertext = self::box($message, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
ParagonIE_Sodium_Compat::memzero($ephemeralSK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$ephemeralKeypair = null;
$ephemeralSK = null;
$nonce = null;
}
return $ephemeralPK . $ciphertext;
}
/**
* Opens a message encrypted via box_seal().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal_open($message, $keypair)
{
/** @var string $ephemeralPK */
$ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32);
/** @var string $ciphertext (ciphertext + MAC) */
$ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32);
/** @var string $secretKey */
$secretKey = self::box_secretkey($keypair);
/** @var string $publicKey */
$publicKey = self::box_publickey($keypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair */
$keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
/** @var string $m */
$m = self::box_open($ciphertext, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($secretKey);
ParagonIE_Sodium_Compat::memzero($ephemeralPK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$secretKey = null;
$ephemeralPK = null;
$nonce = null;
}
return $m;
}
/**
* Used by crypto_box() to get the crypto_secretbox() key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_beforenm($sk, $pk)
{
return ParagonIE_Sodium_Core_HSalsa20::hsalsa20(
str_repeat("\x00", 16),
self::scalarmult($sk, $pk)
);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @return string
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function box_keypair()
{
$sKey = random_bytes(32);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seed_keypair($seed)
{
$sKey = ParagonIE_Sodium_Core_Util::substr(
hash('sha512', $seed, true),
0,
32
);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
* @throws TypeError
*/
public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey)
{
return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) .
ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_secretkey($keypair)
{
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) {
throw new RangeException(
'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_publickey($keypair)
{
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new RangeException(
'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function box_publickey_from_secretkey($sKey)
{
if (ParagonIE_Sodium_Core_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
throw new RangeException(
'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
);
}
return self::scalarmult_base($sKey);
}
/**
* Decrypt a message encrypted with box().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_open($ciphertext, $nonce, $keypair)
{
return self::secretbox_open(
$ciphertext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
}
/**
* Calculate a BLAKE2b hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string|null $key
* @param int $outlen
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash($message, $key = '', $outlen = 32)
{
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
/** @var SplFixedArray $k */
$k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $in */
$in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen);
ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count());
/** @var SplFixedArray $out */
$out = new SplFixedArray($outlen);
$out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
}
/**
* Finalize a BLAKE2b hashing context, returning the hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param int $outlen
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_final($ctx, $outlen = 32)
{
if (!is_string($ctx)) {
throw new TypeError('Context must be a string');
}
$out = new SplFixedArray($outlen);
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $out */
$out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init($key = '', $outputLength = 32)
{
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength);
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @param string $salt
* @param string $personal
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init_salt_personal(
$key = '',
$outputLength = 32,
$salt = '',
$personal = ''
) {
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
if (!empty($salt)) {
$s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt);
} else {
$s = null;
}
if (!empty($salt)) {
$p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal);
} else {
$p = null;
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p);
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
}
/**
* Update a hashing context for BLAKE2b with $message
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param string $message
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_update($ctx, $message)
{
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $in */
$in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
ParagonIE_Sodium_Core_BLAKE2b::update($context, $in, $in->count());
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context);
}
/**
* Libsodium's crypto_kx().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $my_sk
* @param string $their_pk
* @param string $client_pk
* @param string $server_pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk)
{
return ParagonIE_Sodium_Compat::crypto_generichash(
ParagonIE_Sodium_Compat::crypto_scalarmult($my_sk, $their_pk) .
$client_pk .
$server_pk
);
}
/**
* ECDH over Curve25519
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult($sKey, $pKey)
{
$q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* ECDH over Curve25519, using the basepoint.
* Used to get a secret key from a public key.
*
* @param string $secret
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult_base($secret)
{
$q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* This throws an Error if a zero public key was passed to the function.
*
* @param string $q
* @return void
* @throws SodiumException
* @throws TypeError
*/
protected static function scalarmult_throw_if_zero($q)
{
$d = 0;
for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
$d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]);
}
/* branch-free variant of === 0 */
if (-(1 & (($d - 1) >> 8))) {
throw new SodiumException('Zero public key is not allowed');
}
}
/**
* XSalsa20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox($plaintext, $nonce, $key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor(
$block0,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$block0,
self::secretbox_xsalsa20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core_Util::substr(
$plaintext,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1,
$subkey
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_open($ciphertext, $nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core_Util::xorStrings(
ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt the rest.
$m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core_Util::substr(
$c,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1,
(string) $subkey
);
}
return $m;
}
/**
* XChaCha20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
$block0,
$nonceLast,
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$block0,
self::secretbox_xchacha20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core_Util::substr(
$plaintext,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
$nonceLast,
$subkey,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
64,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core_Util::xorStrings(
ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt the rest.
$m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core_Util::substr(
$c,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
(string) $subkey,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
return $m;
}
/**
* @param string $key
* @return array<int, string> Returns a state and a header.
* @throws Exception
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_init_push($key)
{
# randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
$out = random_bytes(24);
# crypto_core_hchacha20(state->k, out, k, NULL);
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key);
$state = new ParagonIE_Sodium_Core_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4)
);
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$state->counterReset();
# memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
return array(
$state->toString(),
$out
);
}
/**
* @param string $key
* @param string $header
* @return string Returns a state.
* @throws Exception
*/
public static function secretstream_xchacha20poly1305_init_pull($key, $header)
{
# crypto_core_hchacha20(state->k, in, k, NULL);
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($header, 0, 16),
$key
);
$state = new ParagonIE_Sodium_Core_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core_Util::substr($header, 16)
);
$state->counterReset();
# memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
# return 0;
return $state->toString();
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
{
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
# crypto_onetimeauth_poly1305_state poly1305_state;
# unsigned char block[64U];
# unsigned char slen[8U];
# unsigned char *c;
# unsigned char *mac;
$msglen = ParagonIE_Sodium_Core_Util::strlen($msg);
$aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# if (outlen_p != NULL) {
# *outlen_p = 0U;
# }
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
# memset(block, 0, sizeof block);
# block[0] = tag;
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
# state->nonce, 1U, state->k);
$block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(1)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
$auth->update($block);
# out[0] = block[0];
$out = $block[0];
# c = out + (sizeof tag);
# crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
$cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$msg,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(2)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
$auth->update($cipher);
$out .= $cipher;
unset($cipher);
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
$slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
$slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$auth->update($slen);
# mac = c + mlen;
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
$mac = $auth->finish();
$out .= $mac;
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
unset($auth);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
# if (outlen_p != NULL) {
# *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
# }
return $out;
}
/**
* @param string $state
* @param string $cipher
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
{
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
$cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher);
# mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
$msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
$aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
# memset(block, 0, sizeof block);
# block[0] = in[0];
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
# state->nonce, 1U, state->k);
$block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$cipher[0] . str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(1)
);
# tag = block[0];
# block[0] = in[0];
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
$tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]);
$block[0] = $cipher[0];
$auth->update($block);
# c = in + (sizeof tag);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
$auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen));
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
$slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
$auth->update($slen);
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
$mac = $auth->finish();
# stored_mac = c + mlen;
# if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
# sodium_memzero(mac, sizeof mac);
# return -1;
# }
$stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16);
if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) {
return false;
}
# crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
$out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(2)
);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
return array($out, $tag);
}
/**
* @param string $state
* @return void
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_rekey(&$state)
{
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
# unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
# crypto_secretstream_xchacha20poly1305_INONCEBYTES];
# size_t i;
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# new_key_and_inonce[i] = state->k[i];
# }
$new_key_and_inonce = $st->getKey();
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
# STATE_INONCE(state)[i];
# }
$new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8);
# crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
# sizeof new_key_and_inonce,
# state->nonce, state->k);
$st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$new_key_and_inonce,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(0)
));
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# state->k[i] = new_key_and_inonce[i];
# }
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# STATE_INONCE(state)[i] =
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
# }
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$st->counterReset();
$state = $st->toString();
}
/**
* Detached Ed25519 signature.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk);
}
/**
* Attached Ed25519 signature. (Returns a signed message.)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk);
}
/**
* Opens a signed message. If valid, returns the message.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signedMessage
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($signedMessage, $pk)
{
return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage, $pk);
}
/**
* Verify a detached signature of a given message and public key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function sign_verify_detached($signature, $message, $pk)
{
return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature, $message, $pk);
}
}
<?php
namespace ParagonIE\Sodium;
class Compat extends \ParagonIE_Sodium_Compat
{
}
[02-Dec-2025 10:42:38 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_File" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/File.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/File.php on line 4
[02-Dec-2025 10:42:38 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Crypto" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Crypto.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Crypto.php on line 4
[02-Dec-2025 10:42:38 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Compat" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Compat.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Compat.php on line 4
<?php
namespace ParagonIE\Sodium;
class File extends \ParagonIE_Sodium_File
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Xsalsa20 extends \ParagonIE_Sodium_Core_XSalsa20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class X25519 extends \ParagonIE_Sodium_Core_X25519
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Ed25519 extends \ParagonIE_Sodium_Core_Ed25519
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Poly1305 extends \ParagonIE_Sodium_Core_Poly1305
{
}
<?php
namespace ParagonIE\Sodium\Core;
class BLAKE2b extends \ParagonIE_Sodium_Core_BLAKE2b
{
}
<?php
namespace ParagonIE\Sodium\Core;
class SipHash extends \ParagonIE_Sodium_Core_SipHash
{
}
[02-Dec-2025 10:42:39 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_XChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/XChaCha20.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/XChaCha20.php on line 4
[02-Dec-2025 10:42:39 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_BLAKE2b" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/BLAKE2b.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/BLAKE2b.php on line 4
[02-Dec-2025 10:42:39 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_XSalsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Xsalsa20.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Xsalsa20.php on line 4
[02-Dec-2025 10:42:39 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/ChaCha20.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/ChaCha20.php on line 4
[02-Dec-2025 10:42:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Poly1305" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Poly1305.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Poly1305.php on line 4
[02-Dec-2025 10:42:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_HChaCha20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/HChaCha20.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/HChaCha20.php on line 4
[02-Dec-2025 10:42:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Salsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Salsa20.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Salsa20.php on line 4
[02-Dec-2025 10:42:40 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Ed25519" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Ed25519.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Ed25519.php on line 4
[02-Dec-2025 10:42:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_SipHash" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/SipHash.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/SipHash.php on line 4
[02-Dec-2025 10:42:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Util.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Util.php on line 4
[02-Dec-2025 10:42:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_X25519" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/X25519.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/X25519.php on line 4
[02-Dec-2025 10:42:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519.php on line 4
[02-Dec-2025 10:42:41 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_HSalsa20" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/HSalsa20.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/HSalsa20.php on line 4
[02-Dec-2025 10:42:42 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20_Ctx" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/ChaCha20/Ctx.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/ChaCha20/Ctx.php on line 4
[02-Dec-2025 10:42:42 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_ChaCha20_IetfCtx" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/ChaCha20/IetfCtx.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/ChaCha20/IetfCtx.php on line 4
<?php
namespace ParagonIE\Sodium\Core\ChaCha20;
class IetfCtx extends \ParagonIE_Sodium_Core_ChaCha20_IetfCtx
{
}
<?php
namespace ParagonIE\Sodium\Core\ChaCha20;
class Ctx extends \ParagonIE_Sodium_Core_ChaCha20_Ctx
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Util extends \ParagonIE_Sodium_Core_Util
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Salsa20 extends \ParagonIE_Sodium_Core_Salsa20
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519;
class Fe extends \ParagonIE_Sodium_Core_Curve25519_Fe
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519;
class H extends \ParagonIE_Sodium_Core_Curve25519_H
{
}
[02-Dec-2025 10:42:43 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_Fe" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Fe.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Fe.php on line 4
[02-Dec-2025 10:42:43 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_H" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/H.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/H.php on line 4
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class Precomp extends \ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
}
[02-Dec-2025 10:42:43 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_Ge_Precomp" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/Precomp.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/Precomp.php on line 4
[02-Dec-2025 10:42:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_Ge_P1p1" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/P1p1.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/P1p1.php on line 4
[02-Dec-2025 10:42:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_Ge_P2" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/P2.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/P2.php on line 4
[02-Dec-2025 10:42:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_Ge_P3" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/P3.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/P3.php on line 4
[02-Dec-2025 10:42:44 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Curve25519_Ge_Cached" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/Cached.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Curve25519/Ge/Cached.php on line 4
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P1p1 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class Cached extends \ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P3 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P2 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
}
<?php
namespace ParagonIE\Sodium\Core;
class HChaCha20 extends \ParagonIE_Sodium_Core_HChaCha20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Curve25519 extends \ParagonIE_Sodium_Core_Curve25519
{
}
<?php
namespace ParagonIE\Sodium\Core;
class XChaCha20 extends \ParagonIE_Sodium_Core_XChaCha20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class HSalsa20 extends \ParagonIE_Sodium_Core_HSalsa20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class ChaCha20 extends \ParagonIE_Sodium_Core_ChaCha20
{
}
[02-Dec-2025 10:42:45 America/Bogota] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Poly1305_State" not found in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Poly1305/State.php:4
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sodium_compat/namespaced/Core/Poly1305/State.php on line 4
<?php
namespace ParagonIE\Sodium\Core\Poly1305;
class State extends \ParagonIE_Sodium_Core_Poly1305_State
{
}
<?php
namespace ParagonIE\Sodium;
class Crypto extends \ParagonIE_Sodium_Crypto
{
}
<?php
/*
This file should only ever be loaded on PHP 7+
*/
if (PHP_VERSION_ID < 70000) {
return;
}
spl_autoload_register(function ($class) {
$namespace = 'ParagonIE_Sodium_';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = dirname(__FILE__) . '/src/' . str_replace('_', '/', $relative_class) . '.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
});
<?php
require_once dirname(dirname(__FILE__)) . '/autoload.php';
/**
* This file will monkey patch the pure-PHP implementation in place of the
* PECL functions and constants, but only if they do not already exist.
*
* Thus, the functions or constants just proxy to the appropriate
* ParagonIE_Sodium_Compat method or class constant, respectively.
*/
foreach (array(
'BASE64_VARIANT_ORIGINAL',
'BASE64_VARIANT_ORIGINAL_NO_PADDING',
'BASE64_VARIANT_URLSAFE',
'BASE64_VARIANT_URLSAFE_NO_PADDING',
'CRYPTO_AEAD_AES256GCM_KEYBYTES',
'CRYPTO_AEAD_AES256GCM_NSECBYTES',
'CRYPTO_AEAD_AES256GCM_NPUBBYTES',
'CRYPTO_AEAD_AES256GCM_ABYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_ABYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES',
'CRYPTO_AUTH_BYTES',
'CRYPTO_AUTH_KEYBYTES',
'CRYPTO_BOX_SEALBYTES',
'CRYPTO_BOX_SECRETKEYBYTES',
'CRYPTO_BOX_PUBLICKEYBYTES',
'CRYPTO_BOX_KEYPAIRBYTES',
'CRYPTO_BOX_MACBYTES',
'CRYPTO_BOX_NONCEBYTES',
'CRYPTO_BOX_SEEDBYTES',
'CRYPTO_KDF_BYTES_MIN',
'CRYPTO_KDF_BYTES_MAX',
'CRYPTO_KDF_CONTEXTBYTES',
'CRYPTO_KDF_KEYBYTES',
'CRYPTO_KX_BYTES',
'CRYPTO_KX_KEYPAIRBYTES',
'CRYPTO_KX_PRIMITIVE',
'CRYPTO_KX_SEEDBYTES',
'CRYPTO_KX_PUBLICKEYBYTES',
'CRYPTO_KX_SECRETKEYBYTES',
'CRYPTO_KX_SESSIONKEYBYTES',
'CRYPTO_GENERICHASH_BYTES',
'CRYPTO_GENERICHASH_BYTES_MIN',
'CRYPTO_GENERICHASH_BYTES_MAX',
'CRYPTO_GENERICHASH_KEYBYTES',
'CRYPTO_GENERICHASH_KEYBYTES_MIN',
'CRYPTO_GENERICHASH_KEYBYTES_MAX',
'CRYPTO_PWHASH_SALTBYTES',
'CRYPTO_PWHASH_STRPREFIX',
'CRYPTO_PWHASH_ALG_ARGON2I13',
'CRYPTO_PWHASH_ALG_ARGON2ID13',
'CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_MEMLIMIT_MODERATE',
'CRYPTO_PWHASH_OPSLIMIT_MODERATE',
'CRYPTO_PWHASH_MEMLIMIT_SENSITIVE',
'CRYPTO_PWHASH_OPSLIMIT_SENSITIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE',
'CRYPTO_SCALARMULT_BYTES',
'CRYPTO_SCALARMULT_SCALARBYTES',
'CRYPTO_SHORTHASH_BYTES',
'CRYPTO_SHORTHASH_KEYBYTES',
'CRYPTO_SECRETBOX_KEYBYTES',
'CRYPTO_SECRETBOX_MACBYTES',
'CRYPTO_SECRETBOX_NONCEBYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX',
'CRYPTO_SIGN_BYTES',
'CRYPTO_SIGN_SEEDBYTES',
'CRYPTO_SIGN_PUBLICKEYBYTES',
'CRYPTO_SIGN_SECRETKEYBYTES',
'CRYPTO_SIGN_KEYPAIRBYTES',
'CRYPTO_STREAM_KEYBYTES',
'CRYPTO_STREAM_NONCEBYTES',
'CRYPTO_STREAM_XCHACHA20_KEYBYTES',
'CRYPTO_STREAM_XCHACHA20_NONCEBYTES',
'LIBRARY_MAJOR_VERSION',
'LIBRARY_MINOR_VERSION',
'LIBRARY_VERSION_MAJOR',
'LIBRARY_VERSION_MINOR',
'VERSION_STRING'
) as $constant
) {
if (!defined("SODIUM_$constant") && defined("ParagonIE_Sodium_Compat::$constant")) {
define("SODIUM_$constant", constant("ParagonIE_Sodium_Compat::$constant"));
}
}
if (!is_callable('sodium_add')) {
/**
* @see ParagonIE_Sodium_Compat::add()
* @param string $string1
* @param string $string2
* @return void
* @throws SodiumException
*/
function sodium_add(
#[\SensitiveParameter]
&$string1,
#[\SensitiveParameter]
$string2
) {
ParagonIE_Sodium_Compat::add($string1, $string2);
}
}
if (!is_callable('sodium_base642bin')) {
/**
* @see ParagonIE_Sodium_Compat::bin2base64()
* @param string $string
* @param int $variant
* @param string $ignore
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_base642bin(
#[\SensitiveParameter]
$string,
$variant,
$ignore =''
) {
return ParagonIE_Sodium_Compat::base642bin($string, $variant, $ignore);
}
}
if (!is_callable('sodium_bin2base64')) {
/**
* @see ParagonIE_Sodium_Compat::bin2base64()
* @param string $string
* @param int $variant
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_bin2base64(
#[\SensitiveParameter]
$string,
$variant
) {
return ParagonIE_Sodium_Compat::bin2base64($string, $variant);
}
}
if (!is_callable('sodium_bin2hex')) {
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_bin2hex(
#[\SensitiveParameter]
$string
) {
return ParagonIE_Sodium_Compat::bin2hex($string);
}
}
if (!is_callable('sodium_compare')) {
/**
* @see ParagonIE_Sodium_Compat::compare()
* @param string $string1
* @param string $string2
* @return int
* @throws SodiumException
* @throws TypeError
*/
function sodium_compare(
#[\SensitiveParameter]
$string1,
#[\SensitiveParameter]
$string2
) {
return ParagonIE_Sodium_Compat::compare($string1, $string2);
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_aes256gcm_decrypt(
$ciphertext,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
if (($ex instanceof SodiumException) && ($ex->getMessage() === 'AES-256-GCM is not available')) {
throw $ex;
}
return false;
}
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aes256gcm_encrypt(
#[\SensitiveParameter]
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt($message, $additional_data, $nonce, $key);
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_is_available')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available()
* @return bool
*/
function sodium_crypto_aead_aes256gcm_is_available()
{
return ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available();
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_chacha20poly1305_decrypt(
$ciphertext,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_chacha20poly1305_encrypt(
#[\SensitiveParameter]
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_aead_chacha20poly1305_keygen()
{
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_keygen();
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_chacha20poly1305_ietf_decrypt(
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt(
$message,
$additional_data,
$nonce,
$key
);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_chacha20poly1305_ietf_encrypt(
#[\SensitiveParameter]
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_aead_chacha20poly1305_ietf_keygen()
{
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_keygen();
}
}
if (!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_decrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key,
true
);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
#[\SensitiveParameter]
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt(
$message,
$additional_data,
$nonce,
$key,
true
);
}
}
if (!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_aead_xchacha20poly1305_ietf_keygen()
{
return ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_keygen();
}
}
if (!is_callable('sodium_crypto_auth')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth()
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_auth(
$message,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_auth($message, $key);
}
}
if (!is_callable('sodium_crypto_auth_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_auth_keygen()
{
return ParagonIE_Sodium_Compat::crypto_auth_keygen();
}
}
if (!is_callable('sodium_crypto_auth_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth_verify()
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_auth_verify(
$mac,
$message,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_auth_verify($mac, $message, $key);
}
}
if (!is_callable('sodium_crypto_box')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box()
* @param string $message
* @param string $nonce
* @param string $key_pair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_box($message, $nonce, $key_pair);
}
}
if (!is_callable('sodium_crypto_box_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_keypair()
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_keypair()
{
return ParagonIE_Sodium_Compat::crypto_box_keypair();
}
}
if (!is_callable('sodium_crypto_box_keypair_from_secretkey_and_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey()
* @param string $secret_key
* @param string $public_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_keypair_from_secretkey_and_publickey(
#[\SensitiveParameter]
$secret_key,
$public_key
) {
return ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey($secret_key, $public_key);
}
}
if (!is_callable('sodium_crypto_box_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_open()
* @param string $ciphertext
* @param string $nonce
* @param string $key_pair
* @return string|bool
*/
function sodium_crypto_box_open(
$ciphertext,
$nonce,
#[\SensitiveParameter]
$key_pair
) {
try {
return ParagonIE_Sodium_Compat::crypto_box_open($ciphertext, $nonce, $key_pair);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_box_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey()
* @param string $key_pair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_publickey(
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_box_publickey($key_pair);
}
}
if (!is_callable('sodium_crypto_box_publickey_from_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey()
* @param string $secret_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_publickey_from_secretkey(
#[\SensitiveParameter]
$secret_key
) {
return ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey($secret_key);
}
}
if (!is_callable('sodium_crypto_box_seal')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal()
* @param string $message
* @param string $public_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_seal(
#[\SensitiveParameter]
$message,
$public_key
) {
return ParagonIE_Sodium_Compat::crypto_box_seal($message, $public_key);
}
}
if (!is_callable('sodium_crypto_box_seal_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal_open()
* @param string $message
* @param string $key_pair
* @return string|bool
* @throws SodiumException
*/
function sodium_crypto_box_seal_open(
$message,
#[\SensitiveParameter]
$key_pair
) {
try {
return ParagonIE_Sodium_Compat::crypto_box_seal_open($message, $key_pair);
} catch (SodiumException $ex) {
if ($ex->getMessage() === 'Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.') {
throw $ex;
}
return false;
}
}
}
if (!is_callable('sodium_crypto_box_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_secretkey()
* @param string $key_pair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_secretkey(
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_box_secretkey($key_pair);
}
}
if (!is_callable('sodium_crypto_box_seed_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seed_keypair()
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_seed_keypair(
#[\SensitiveParameter]
$seed
) {
return ParagonIE_Sodium_Compat::crypto_box_seed_keypair($seed);
}
}
if (!is_callable('sodium_crypto_generichash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash()
* @param string $message
* @param string|null $key
* @param int $length
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash(
$message,
#[\SensitiveParameter]
$key = null,
$length = 32
) {
return ParagonIE_Sodium_Compat::crypto_generichash($message, $key, $length);
}
}
if (!is_callable('sodium_crypto_generichash_final')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_final()
* @param string|null $state
* @param int $outputLength
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash_final(&$state, $outputLength = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash_final($state, $outputLength);
}
}
if (!is_callable('sodium_crypto_generichash_init')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_init()
* @param string|null $key
* @param int $length
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash_init(
#[\SensitiveParameter]
$key = null,
$length = 32
) {
return ParagonIE_Sodium_Compat::crypto_generichash_init($key, $length);
}
}
if (!is_callable('sodium_crypto_generichash_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_generichash_keygen()
{
return ParagonIE_Sodium_Compat::crypto_generichash_keygen();
}
}
if (!is_callable('sodium_crypto_generichash_update')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_update()
* @param string|null $state
* @param string $message
* @return void
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash_update(
#[\SensitiveParameter]
&$state,
$message = ''
) {
ParagonIE_Sodium_Compat::crypto_generichash_update($state, $message);
}
}
if (!is_callable('sodium_crypto_kdf_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kdf_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_kdf_keygen()
{
return ParagonIE_Sodium_Compat::crypto_kdf_keygen();
}
}
if (!is_callable('sodium_crypto_kdf_derive_from_key')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key()
* @param int $subkey_length
* @param int $subkey_id
* @param string $context
* @param string $key
* @return string
* @throws Exception
*/
function sodium_crypto_kdf_derive_from_key(
$subkey_length,
$subkey_id,
$context,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key(
$subkey_length,
$subkey_id,
$context,
$key
);
}
}
if (!is_callable('sodium_crypto_kx')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kx()
* @param string $my_secret
* @param string $their_public
* @param string $client_public
* @param string $server_public
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_kx(
#[\SensitiveParameter]
$my_secret,
$their_public,
$client_public,
$server_public
) {
return ParagonIE_Sodium_Compat::crypto_kx(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
}
if (!is_callable('sodium_crypto_kx_seed_keypair')) {
/**
* @param string $seed
* @return string
* @throws Exception
*/
function sodium_crypto_kx_seed_keypair(
#[\SensitiveParameter]
$seed
) {
return ParagonIE_Sodium_Compat::crypto_kx_seed_keypair($seed);
}
}
if (!is_callable('sodium_crypto_kx_keypair')) {
/**
* @return string
* @throws Exception
*/
function sodium_crypto_kx_keypair()
{
return ParagonIE_Sodium_Compat::crypto_kx_keypair();
}
}
if (!is_callable('sodium_crypto_kx_client_session_keys')) {
/**
* @param string $client_key_pair
* @param string $server_key
* @return array{0: string, 1: string}
* @throws SodiumException
*/
function sodium_crypto_kx_client_session_keys(
#[\SensitiveParameter]
$client_key_pair,
$server_key
) {
return ParagonIE_Sodium_Compat::crypto_kx_client_session_keys($client_key_pair, $server_key);
}
}
if (!is_callable('sodium_crypto_kx_server_session_keys')) {
/**
* @param string $server_key_pair
* @param string $client_key
* @return array{0: string, 1: string}
* @throws SodiumException
*/
function sodium_crypto_kx_server_session_keys(
#[\SensitiveParameter]
$server_key_pair,
$client_key
) {
return ParagonIE_Sodium_Compat::crypto_kx_server_session_keys($server_key_pair, $client_key);
}
}
if (!is_callable('sodium_crypto_kx_secretkey')) {
/**
* @param string $key_pair
* @return string
* @throws Exception
*/
function sodium_crypto_kx_secretkey(
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_kx_secretkey($key_pair);
}
}
if (!is_callable('sodium_crypto_kx_publickey')) {
/**
* @param string $key_pair
* @return string
* @throws Exception
*/
function sodium_crypto_kx_publickey(
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_kx_publickey($key_pair);
}
}
if (!is_callable('sodium_crypto_pwhash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash()
* @param int $length
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @param int|null $algo
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash(
$length,
#[\SensitiveParameter]
$passwd,
$salt,
$opslimit,
$memlimit,
$algo = null
) {
return ParagonIE_Sodium_Compat::crypto_pwhash($length, $passwd, $salt, $opslimit, $memlimit, $algo);
}
}
if (!is_callable('sodium_crypto_pwhash_str')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_str(
#[\SensitiveParameter]
$passwd,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_str($passwd, $opslimit, $memlimit);
}
}
if (!is_callable('sodium_crypto_pwhash_str_needs_rehash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash()
* @param string $hash
* @param int $opslimit
* @param int $memlimit
* @return bool
*
* @throws SodiumException
*/
function sodium_crypto_pwhash_str_needs_rehash(
#[\SensitiveParameter]
$hash,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit);
}
}
if (!is_callable('sodium_crypto_pwhash_str_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_str_verify(
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$hash
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_str_verify($passwd, $hash);
}
}
if (!is_callable('sodium_crypto_pwhash_scryptsalsa208sha256')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256()
* @param int $length
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_scryptsalsa208sha256(
$length,
#[\SensitiveParameter]
$passwd,
$salt,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256(
$length,
$passwd,
$salt,
$opslimit,
$memlimit
);
}
}
if (!is_callable('sodium_crypto_pwhash_scryptsalsa208sha256_str')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_scryptsalsa208sha256_str(
#[\SensitiveParameter]
$passwd,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit);
}
}
if (!is_callable('sodium_crypto_pwhash_scryptsalsa208sha256_str_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_scryptsalsa208sha256_str_verify(
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$hash
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash);
}
}
if (!is_callable('sodium_crypto_scalarmult')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult()
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult(
#[\SensitiveParameter]
$n,
$p
) {
return ParagonIE_Sodium_Compat::crypto_scalarmult($n, $p);
}
}
if (!is_callable('sodium_crypto_scalarmult_base')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_base()
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult_base(
#[\SensitiveParameter]
$n
) {
return ParagonIE_Sodium_Compat::crypto_scalarmult_base($n);
}
}
if (!is_callable('sodium_crypto_secretbox')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_secretbox(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_secretbox($message, $nonce, $key);
}
}
if (!is_callable('sodium_crypto_secretbox_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_secretbox_keygen()
{
return ParagonIE_Sodium_Compat::crypto_secretbox_keygen();
}
}
if (!is_callable('sodium_crypto_secretbox_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox_open()
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_secretbox_open(
$ciphertext,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_secretbox_open($ciphertext, $nonce, $key);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_push')) {
/**
* @param string $key
* @return array<int, string>
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_init_push(
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_push($key);
}
}
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_push')) {
/**
* @param string $state
* @param string $message
* @param string $additional_data
* @param int $tag
* @return string
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_push(
#[\SensitiveParameter]
&$state,
#[\SensitiveParameter]
$message,
$additional_data = '',
$tag = 0
) {
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_push(
$state,
$message,
$additional_data,
$tag
);
}
}
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_pull')) {
/**
* @param string $header
* @param string $key
* @return string
* @throws Exception
*/
function sodium_crypto_secretstream_xchacha20poly1305_init_pull(
$header,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
}
}
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_pull')) {
/**
* @param string $state
* @param string $ciphertext
* @param string $additional_data
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_pull(
#[\SensitiveParameter]
&$state,
$ciphertext,
$additional_data = ''
) {
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_pull(
$state,
$ciphertext,
$additional_data
);
}
}
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_rekey')) {
/**
* @param string $state
* @return void
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_rekey(
#[\SensitiveParameter]
&$state
) {
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_rekey($state);
}
}
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_keygen')) {
/**
* @return string
* @throws Exception
*/
function sodium_crypto_secretstream_xchacha20poly1305_keygen()
{
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_keygen();
}
}
if (!is_callable('sodium_crypto_shorthash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_shorthash()
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_shorthash(
$message,
#[\SensitiveParameter]
$key = ''
) {
return ParagonIE_Sodium_Compat::crypto_shorthash($message, $key);
}
}
if (!is_callable('sodium_crypto_shorthash_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_shorthash_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_shorthash_keygen()
{
return ParagonIE_Sodium_Compat::crypto_shorthash_keygen();
}
}
if (!is_callable('sodium_crypto_sign')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign()
* @param string $message
* @param string $secret_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign(
$message,
#[\SensitiveParameter]
$secret_key
) {
return ParagonIE_Sodium_Compat::crypto_sign($message, $secret_key);
}
}
if (!is_callable('sodium_crypto_sign_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_detached()
* @param string $message
* @param string $secret_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_detached(
$message,
#[\SensitiveParameter]
$secret_key
) {
return ParagonIE_Sodium_Compat::crypto_sign_detached($message, $secret_key);
}
}
if (!is_callable('sodium_crypto_sign_keypair_from_secretkey_and_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey()
* @param string $secret_key
* @param string $public_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_keypair_from_secretkey_and_publickey(
#[\SensitiveParameter]
$secret_key,
$public_key
) {
return ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey($secret_key, $public_key);
}
}
if (!is_callable('sodium_crypto_sign_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair()
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_keypair()
{
return ParagonIE_Sodium_Compat::crypto_sign_keypair();
}
}
if (!is_callable('sodium_crypto_sign_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_open()
* @param string $signedMessage
* @param string $public_key
* @return string|bool
*/
function sodium_crypto_sign_open($signedMessage, $public_key)
{
try {
return ParagonIE_Sodium_Compat::crypto_sign_open($signedMessage, $public_key);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_sign_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey()
* @param string $key_pair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_publickey(
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_sign_publickey($key_pair);
}
}
if (!is_callable('sodium_crypto_sign_publickey_from_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey()
* @param string $secret_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_publickey_from_secretkey(
#[\SensitiveParameter]
$secret_key
) {
return ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey($secret_key);
}
}
if (!is_callable('sodium_crypto_sign_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_secretkey()
* @param string $key_pair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_secretkey(
#[\SensitiveParameter]
$key_pair
) {
return ParagonIE_Sodium_Compat::crypto_sign_secretkey($key_pair);
}
}
if (!is_callable('sodium_crypto_sign_seed_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_seed_keypair()
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_seed_keypair(
#[\SensitiveParameter]
$seed
) {
return ParagonIE_Sodium_Compat::crypto_sign_seed_keypair($seed);
}
}
if (!is_callable('sodium_crypto_sign_verify_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_verify_detached()
* @param string $signature
* @param string $message
* @param string $public_key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_verify_detached($signature, $message, $public_key)
{
return ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $message, $public_key);
}
}
if (!is_callable('sodium_crypto_sign_ed25519_pk_to_curve25519')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519()
* @param string $public_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_ed25519_pk_to_curve25519($public_key)
{
return ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519($public_key);
}
}
if (!is_callable('sodium_crypto_sign_ed25519_sk_to_curve25519')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519()
* @param string $secret_key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_ed25519_sk_to_curve25519(
#[\SensitiveParameter]
$secret_key
) {
return ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519($secret_key);
}
}
if (!is_callable('sodium_crypto_stream')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream()
* @param int $length
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream(
$length,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream($length, $nonce, $key);
}
}
if (!is_callable('sodium_crypto_stream_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_stream_keygen()
{
return ParagonIE_Sodium_Compat::crypto_stream_keygen();
}
}
if (!is_callable('sodium_crypto_stream_xor')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xor()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xor(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream_xor($message, $nonce, $key);
}
}
require_once dirname(__FILE__) . '/stream-xchacha20.php';
if (!is_callable('sodium_hex2bin')) {
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @param string $ignore
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_hex2bin(
#[\SensitiveParameter]
$string,
$ignore = ''
) {
return ParagonIE_Sodium_Compat::hex2bin($string, $ignore);
}
}
if (!is_callable('sodium_increment')) {
/**
* @see ParagonIE_Sodium_Compat::increment()
* @param string $string
* @return void
* @throws SodiumException
* @throws TypeError
*/
function sodium_increment(
#[\SensitiveParameter]
&$string
) {
ParagonIE_Sodium_Compat::increment($string);
}
}
if (!is_callable('sodium_library_version_major')) {
/**
* @see ParagonIE_Sodium_Compat::library_version_major()
* @return int
*/
function sodium_library_version_major()
{
return ParagonIE_Sodium_Compat::library_version_major();
}
}
if (!is_callable('sodium_library_version_minor')) {
/**
* @see ParagonIE_Sodium_Compat::library_version_minor()
* @return int
*/
function sodium_library_version_minor()
{
return ParagonIE_Sodium_Compat::library_version_minor();
}
}
if (!is_callable('sodium_version_string')) {
/**
* @see ParagonIE_Sodium_Compat::version_string()
* @return string
*/
function sodium_version_string()
{
return ParagonIE_Sodium_Compat::version_string();
}
}
if (!is_callable('sodium_memcmp')) {
/**
* @see ParagonIE_Sodium_Compat::memcmp()
* @param string $string1
* @param string $string2
* @return int
* @throws SodiumException
* @throws TypeError
*/
function sodium_memcmp(
#[\SensitiveParameter]
$string1,
#[\SensitiveParameter]
$string2
) {
return ParagonIE_Sodium_Compat::memcmp($string1, $string2);
}
}
if (!is_callable('sodium_memzero')) {
/**
* @see ParagonIE_Sodium_Compat::memzero()
* @param string $string
* @return void
* @throws SodiumException
* @throws TypeError
*
* @psalm-suppress ReferenceConstraintViolation
*/
function sodium_memzero(
#[\SensitiveParameter]
&$string
) {
ParagonIE_Sodium_Compat::memzero($string);
}
}
if (!is_callable('sodium_pad')) {
/**
* @see ParagonIE_Sodium_Compat::pad()
* @param string $unpadded
* @param int $block_size
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_pad(
#[\SensitiveParameter]
$unpadded,
$block_size
) {
return ParagonIE_Sodium_Compat::pad($unpadded, $block_size, true);
}
}
if (!is_callable('sodium_unpad')) {
/**
* @see ParagonIE_Sodium_Compat::pad()
* @param string $padded
* @param int $block_size
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_unpad(
#[\SensitiveParameter]
$padded,
$block_size
) {
return ParagonIE_Sodium_Compat::unpad($padded, $block_size, true);
}
}
if (!is_callable('sodium_randombytes_buf')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_buf()
* @param int $amount
* @return string
* @throws Exception
*/
function sodium_randombytes_buf($amount)
{
return ParagonIE_Sodium_Compat::randombytes_buf($amount);
}
}
if (!is_callable('sodium_randombytes_uniform')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_uniform()
* @param int $upperLimit
* @return int
* @throws Exception
*/
function sodium_randombytes_uniform($upperLimit)
{
return ParagonIE_Sodium_Compat::randombytes_uniform($upperLimit);
}
}
if (!is_callable('sodium_randombytes_random16')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_random16()
* @return int
* @throws Exception
*/
function sodium_randombytes_random16()
{
return ParagonIE_Sodium_Compat::randombytes_random16();
}
}
<?php
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_BYTES
);
define('SODIUM_COMPAT_POLYFILLED_RISTRETTO255', true);
}
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_HASHBYTES
);
}
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_SCALARBYTES
);
}
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES
);
}
if (!defined('SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES')) {
define(
'SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES',
ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES
);
}
if (!defined('SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES')) {
define(
'SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES',
ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_RISTRETTO255_BYTES
);
}
if (!is_callable('sodium_crypto_core_ristretto255_add')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_add()
*
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_add(
#[\SensitiveParameter]
$p,
#[\SensitiveParameter]
$q
) {
return ParagonIE_Sodium_Compat::ristretto255_add($p, $q, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_from_hash')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_from_hash()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_from_hash(
#[\SensitiveParameter]
$s
) {
return ParagonIE_Sodium_Compat::ristretto255_from_hash($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_is_valid_point')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_is_valid_point()
*
* @param string $s
* @return bool
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_is_valid_point(
#[\SensitiveParameter]
$s
) {
return ParagonIE_Sodium_Compat::ristretto255_is_valid_point($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_random')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_random()
*
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_random()
{
return ParagonIE_Sodium_Compat::ristretto255_random(true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_add')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_add()
*
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_add(
#[\SensitiveParameter]
$x,
#[\SensitiveParameter]
$y
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_add($x, $y, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_complement')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_complement()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_complement(
#[\SensitiveParameter]
$s
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_complement($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_invert')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_invert()
*
* @param string $p
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_invert(
#[\SensitiveParameter]
$p
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_invert($p, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_mul')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_mul()
*
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_mul(
#[\SensitiveParameter]
$x,
#[\SensitiveParameter]
$y
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_mul($x, $y, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_negate')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_negate()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_negate(
#[\SensitiveParameter]
$s
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_negate($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_random')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_random()
*
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_random()
{
return ParagonIE_Sodium_Compat::ristretto255_scalar_random(true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_reduce')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_reduce()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_reduce(
#[\SensitiveParameter]
$s
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_reduce($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_sub')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_sub()
*
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_sub(
#[\SensitiveParameter]
$x,
#[\SensitiveParameter]
$y
) {
return ParagonIE_Sodium_Compat::ristretto255_scalar_sub($x, $y, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_sub')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_sub()
*
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_sub(
#[\SensitiveParameter]
$p,
#[\SensitiveParameter]
$q
) {
return ParagonIE_Sodium_Compat::ristretto255_sub($p, $q, true);
}
}
if (!is_callable('sodium_crypto_scalarmult_ristretto255')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_ristretto255()
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult_ristretto255(
#[\SensitiveParameter]
$n,
#[\SensitiveParameter]
$p
) {
return ParagonIE_Sodium_Compat::scalarmult_ristretto255($n, $p, true);
}
}
if (!is_callable('sodium_crypto_scalarmult_ristretto255_base')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_ristretto255_base()
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult_ristretto255_base(
#[\SensitiveParameter]
$n
) {
return ParagonIE_Sodium_Compat::scalarmult_ristretto255_base($n, true);
}
}<?php
namespace Sodium;
require_once dirname(dirname(__FILE__)) . '/autoload.php';
use ParagonIE_Sodium_Compat;
const CRYPTO_AEAD_AES256GCM_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_KEYBYTES;
const CRYPTO_AEAD_AES256GCM_NSECBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_NSECBYTES;
const CRYPTO_AEAD_AES256GCM_NPUBBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_NPUBBYTES;
const CRYPTO_AEAD_AES256GCM_ABYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_ABYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES;
const CRYPTO_AUTH_BYTES = ParagonIE_Sodium_Compat::CRYPTO_AUTH_BYTES;
const CRYPTO_AUTH_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_AUTH_KEYBYTES;
const CRYPTO_BOX_SEALBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_SEALBYTES;
const CRYPTO_BOX_SECRETKEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES;
const CRYPTO_BOX_PUBLICKEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES;
const CRYPTO_BOX_KEYPAIRBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES;
const CRYPTO_BOX_MACBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_MACBYTES;
const CRYPTO_BOX_NONCEBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES;
const CRYPTO_BOX_SEEDBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_SEEDBYTES;
const CRYPTO_KX_BYTES = ParagonIE_Sodium_Compat::CRYPTO_KX_BYTES;
const CRYPTO_KX_SEEDBYTES = ParagonIE_Sodium_Compat::CRYPTO_KX_SEEDBYTES;
const CRYPTO_KX_PUBLICKEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_KX_PUBLICKEYBYTES;
const CRYPTO_KX_SECRETKEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_KX_SECRETKEYBYTES;
const CRYPTO_GENERICHASH_BYTES = ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES;
const CRYPTO_GENERICHASH_BYTES_MIN = ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN;
const CRYPTO_GENERICHASH_BYTES_MAX = ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX;
const CRYPTO_GENERICHASH_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES;
const CRYPTO_GENERICHASH_KEYBYTES_MIN = ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN;
const CRYPTO_GENERICHASH_KEYBYTES_MAX = ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX;
const CRYPTO_SCALARMULT_BYTES = ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_BYTES;
const CRYPTO_SCALARMULT_SCALARBYTES = ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_SCALARBYTES;
const CRYPTO_SHORTHASH_BYTES = ParagonIE_Sodium_Compat::CRYPTO_SHORTHASH_BYTES;
const CRYPTO_SHORTHASH_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_SHORTHASH_KEYBYTES;
const CRYPTO_SECRETBOX_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES;
const CRYPTO_SECRETBOX_MACBYTES = ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES;
const CRYPTO_SECRETBOX_NONCEBYTES = ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES;
const CRYPTO_SIGN_BYTES = ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES;
const CRYPTO_SIGN_SEEDBYTES = ParagonIE_Sodium_Compat::CRYPTO_SIGN_SEEDBYTES;
const CRYPTO_SIGN_PUBLICKEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES;
const CRYPTO_SIGN_SECRETKEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES;
const CRYPTO_SIGN_KEYPAIRBYTES = ParagonIE_Sodium_Compat::CRYPTO_SIGN_KEYPAIRBYTES;
const CRYPTO_STREAM_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_STREAM_KEYBYTES;
const CRYPTO_STREAM_NONCEBYTES = ParagonIE_Sodium_Compat::CRYPTO_STREAM_NONCEBYTES;
<?php
if (!is_callable('sodium_crypto_stream_xchacha20')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20()
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xchacha20(
$len,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20($len, $nonce, $key, true);
}
}
if (!is_callable('sodium_crypto_stream_xchacha20_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_stream_xchacha20_keygen()
{
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20_keygen();
}
}
if (!is_callable('sodium_crypto_stream_xchacha20_xor')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xchacha20_xor(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor($message, $nonce, $key, true);
}
}
if (!is_callable('sodium_crypto_stream_xchacha20_xor_ic')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor_ic()
* @param string $message
* @param string $nonce
* @param int $counter
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xchacha20_xor_ic(
#[\SensitiveParameter]
$message,
$nonce,
$counter,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor_ic($message, $nonce, $counter, $key, true);
}
}
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_LIBRARY_MAJOR_VERSION already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 3
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_LIBRARY_MINOR_VERSION already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 4
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_LIBRARY_VERSION already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 5
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_BASE64_VARIANT_ORIGINAL already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 7
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 8
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_BASE64_VARIANT_URLSAFE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 9
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 10
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 11
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_AES256GCM_NSECBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 12
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 13
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_AES256GCM_ABYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 14
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 15
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 16
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 17
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_ABYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 18
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 19
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 20
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 21
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 22
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 23
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 24
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 25
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 26
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AUTH_BYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 27
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_AUTH_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 28
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_SEALBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 29
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_SECRETKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 30
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_PUBLICKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 31
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_KEYPAIRBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 32
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_MACBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 33
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_NONCEBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 34
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_BOX_SEEDBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 35
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KDF_BYTES_MIN already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 36
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KDF_BYTES_MAX already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 37
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KDF_CONTEXTBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 38
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KDF_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 39
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KX_SEEDBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 42
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KX_KEYPAIRBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 43
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KX_PUBLICKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 44
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KX_SECRETKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 45
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_KX_SESSIONKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 46
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_GENERICHASH_BYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 47
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_GENERICHASH_BYTES_MIN already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 48
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_GENERICHASH_BYTES_MAX already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 49
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_GENERICHASH_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 50
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MIN already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 51
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MAX already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 52
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SALTBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 53
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_STRPREFIX already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 54
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13 already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 55
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 56
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 57
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 58
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 59
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 60
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 61
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 62
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 63
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 64
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 65
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 66
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 67
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 68
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SCALARMULT_BYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 69
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SCALARMULT_SCALARBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 70
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SHORTHASH_BYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 71
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SHORTHASH_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 72
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETBOX_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 73
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETBOX_MACBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 74
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETBOX_NONCEBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 75
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 76
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 77
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 78
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 79
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 81
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 82
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 83
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SIGN_BYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 84
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SIGN_SEEDBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 85
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 86
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SIGN_SECRETKEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 87
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_SIGN_KEYPAIRBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 88
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_STREAM_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 89
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_STREAM_NONCEBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 90
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 91
[02-Dec-2025 10:42:45 America/Bogota] PHP Warning: Constant SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES already defined in /home/coopserp/public_html/wp-includes/sodium_compat/lib/php72compat_const.php on line 92
<?php
require_once dirname(dirname(__FILE__)) . '/autoload.php';
/**
* This file will monkey patch the pure-PHP implementation in place of the
* PECL functions and constants, but only if they do not already exist.
*
* Thus, the functions or constants just proxy to the appropriate
* ParagonIE_Sodium_Compat method or class constant, respectively.
*/
foreach (array(
'CRYPTO_AEAD_AESGIS128L_KEYBYTES',
'CRYPTO_AEAD_AESGIS128L_NSECBYTES',
'CRYPTO_AEAD_AESGIS128L_NPUBBYTES',
'CRYPTO_AEAD_AESGIS128L_ABYTES',
'CRYPTO_AEAD_AESGIS256_KEYBYTES',
'CRYPTO_AEAD_AESGIS256_NSECBYTES',
'CRYPTO_AEAD_AESGIS256_NPUBBYTES',
'CRYPTO_AEAD_AESGIS256_ABYTES',
) as $constant
) {
if (!defined("SODIUM_$constant") && defined("ParagonIE_Sodium_Compat::$constant")) {
define("SODIUM_$constant", constant("ParagonIE_Sodium_Compat::$constant"));
}
}
if (!is_callable('sodium_crypto_aead_aegis128l_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
*/
function sodium_crypto_aead_aegis128l_decrypt(
$ciphertext,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis128l_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aegis128l_encrypt(
#[\SensitiveParameter]
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis256_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
*/
function sodium_crypto_aead_aegis256_decrypt(
$ciphertext,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis256_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aegis256_encrypt(
#[\SensitiveParameter]
$message,
$additional_data,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
<?php
namespace Sodium;
require_once dirname(dirname(__FILE__)) . '/autoload.php';
use ParagonIE_Sodium_Compat;
/**
* This file will monkey patch the pure-PHP implementation in place of the
* PECL functions, but only if they do not already exist.
*
* Thus, the functions just proxy to the appropriate ParagonIE_Sodium_Compat
* method.
*/
if (!is_callable('\\Sodium\\bin2hex')) {
/**
* @see ParagonIE_Sodium_Compat::bin2hex()
* @param string $string
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function bin2hex(
#[\SensitiveParameter]
$string
) {
return ParagonIE_Sodium_Compat::bin2hex($string);
}
}
if (!is_callable('\\Sodium\\compare')) {
/**
* @see ParagonIE_Sodium_Compat::compare()
* @param string $a
* @param string $b
* @return int
* @throws \SodiumException
* @throws \TypeError
*/
function compare(
#[\SensitiveParameter]
$a,
#[\SensitiveParameter]
$b
) {
return ParagonIE_Sodium_Compat::compare($a, $b);
}
}
if (!is_callable('\\Sodium\\crypto_aead_aes256gcm_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_aead_aes256gcm_decrypt(
$message,
$assocData,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt($message, $assocData, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_aead_aes256gcm_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_aead_aes256gcm_encrypt(
#[\SensitiveParameter]
$message,
$assocData,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt($message, $assocData, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_aead_aes256gcm_is_available')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available()
* @return bool
*/
function crypto_aead_aes256gcm_is_available()
{
return ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available();
}
}
if (!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_aead_chacha20poly1305_decrypt(
$message,
$assocData,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt($message, $assocData, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_aead_chacha20poly1305_encrypt(
#[\SensitiveParameter]
$message,
$assocData,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt($message, $assocData, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_aead_chacha20poly1305_ietf_decrypt(
$message,
$assocData,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt($message, $assocData, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_aead_chacha20poly1305_ietf_encrypt(
#[\SensitiveParameter]
$message,
$assocData,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt($message, $assocData, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_auth')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth()
* @param string $message
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_auth(
$message,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_auth($message, $key);
}
}
if (!is_callable('\\Sodium\\crypto_auth_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth_verify()
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_auth_verify(
$mac,
$message,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_auth_verify($mac, $message, $key);
}
}
if (!is_callable('\\Sodium\\crypto_box')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box()
* @param string $message
* @param string $nonce
* @param string $kp
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$kp
) {
return ParagonIE_Sodium_Compat::crypto_box($message, $nonce, $kp);
}
}
if (!is_callable('\\Sodium\\crypto_box_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_keypair()
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_keypair()
{
return ParagonIE_Sodium_Compat::crypto_box_keypair();
}
}
if (!is_callable('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey()
* @param string $sk
* @param string $pk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_keypair_from_secretkey_and_publickey(
#[\SensitiveParameter]
$sk,
$pk
) {
return ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey($sk, $pk);
}
}
if (!is_callable('\\Sodium\\crypto_box_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_open()
* @param string $message
* @param string $nonce
* @param string $kp
* @return string|bool
*/
function crypto_box_open(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$kp
) {
try {
return ParagonIE_Sodium_Compat::crypto_box_open($message, $nonce, $kp);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_box_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_publickey(
#[\SensitiveParameter]
$keypair
) {
return ParagonIE_Sodium_Compat::crypto_box_publickey($keypair);
}
}
if (!is_callable('\\Sodium\\crypto_box_publickey_from_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey()
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_publickey_from_secretkey(
#[\SensitiveParameter]
$sk
) {
return ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey($sk);
}
}
if (!is_callable('\\Sodium\\crypto_box_seal')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal_open()
* @param string $message
* @param string $publicKey
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_seal(
#[\SensitiveParameter]
$message,
$publicKey
) {
return ParagonIE_Sodium_Compat::crypto_box_seal($message, $publicKey);
}
}
if (!is_callable('\\Sodium\\crypto_box_seal_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal_open()
* @param string $message
* @param string $kp
* @return string|bool
*/
function crypto_box_seal_open(
$message,
#[\SensitiveParameter]
$kp
) {
try {
return ParagonIE_Sodium_Compat::crypto_box_seal_open($message, $kp);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_box_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_secretkey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_secretkey(
#[\SensitiveParameter]
$keypair
) {
return ParagonIE_Sodium_Compat::crypto_box_secretkey($keypair);
}
}
if (!is_callable('\\Sodium\\crypto_generichash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash()
* @param string $message
* @param string|null $key
* @param int $outLen
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash(
$message,
#[\SensitiveParameter]
$key = null,
$outLen = 32
) {
return ParagonIE_Sodium_Compat::crypto_generichash($message, $key, $outLen);
}
}
if (!is_callable('\\Sodium\\crypto_generichash_final')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_final()
* @param string|null $ctx
* @param int $outputLength
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash_final(
#[\SensitiveParameter]
&$ctx,
$outputLength = 32
) {
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength);
}
}
if (!is_callable('\\Sodium\\crypto_generichash_init')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_init()
* @param string|null $key
* @param int $outLen
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash_init(
#[\SensitiveParameter]
$key = null,
$outLen = 32
) {
return ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outLen);
}
}
if (!is_callable('\\Sodium\\crypto_generichash_update')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_update()
* @param string|null $ctx
* @param string $message
* @return void
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash_update(
#[\SensitiveParameter]
&$ctx,
$message = ''
) {
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $message);
}
}
if (!is_callable('\\Sodium\\crypto_kx')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kx()
* @param string $my_secret
* @param string $their_public
* @param string $client_public
* @param string $server_public
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_kx(
#[\SensitiveParameter]
$my_secret,
$their_public,
$client_public,
$server_public
) {
return ParagonIE_Sodium_Compat::crypto_kx(
$my_secret,
$their_public,
$client_public,
$server_public,
true
);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash()
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash(
$outlen,
#[\SensitiveParameter]
$passwd,
$salt,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_str')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_str(
#[\SensitiveParameter]
$passwd,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_str($passwd, $opslimit, $memlimit);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_str_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_str_verify(
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$hash
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_str_verify($passwd, $hash);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_scryptsalsa208sha256')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256()
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_scryptsalsa208sha256(
$outlen,
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$salt,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_scryptsalsa208sha256_str(
#[\SensitiveParameter]
$passwd,
$opslimit,
$memlimit
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_scryptsalsa208sha256_str_verify(
#[\SensitiveParameter]
$passwd,
#[\SensitiveParameter]
$hash
) {
return ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash);
}
}
if (!is_callable('\\Sodium\\crypto_scalarmult')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult()
* @param string $n
* @param string $p
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_scalarmult(
#[\SensitiveParameter]
$n,
$p
) {
return ParagonIE_Sodium_Compat::crypto_scalarmult($n, $p);
}
}
if (!is_callable('\\Sodium\\crypto_scalarmult_base')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_base()
* @param string $n
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_scalarmult_base(
#[\SensitiveParameter]
$n
) {
return ParagonIE_Sodium_Compat::crypto_scalarmult_base($n);
}
}
if (!is_callable('\\Sodium\\crypto_secretbox')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_secretbox(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_secretbox($message, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_secretbox_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox_open()
* @param string $message
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_secretbox_open(
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
try {
return ParagonIE_Sodium_Compat::crypto_secretbox_open($message, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_shorthash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_shorthash()
* @param string $message
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_shorthash(
$message,
#[\SensitiveParameter]
$key = ''
) {
return ParagonIE_Sodium_Compat::crypto_shorthash($message, $key);
}
}
if (!is_callable('\\Sodium\\crypto_sign')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign()
* @param string $message
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign(
$message,
#[\SensitiveParameter]
$sk
) {
return ParagonIE_Sodium_Compat::crypto_sign($message, $sk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_detached()
* @param string $message
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_detached(
$message,
#[\SensitiveParameter]
$sk
) {
return ParagonIE_Sodium_Compat::crypto_sign_detached($message, $sk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair()
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_keypair()
{
return ParagonIE_Sodium_Compat::crypto_sign_keypair();
}
}
if (!is_callable('\\Sodium\\crypto_sign_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_open()
* @param string $signedMessage
* @param string $pk
* @return string|bool
*/
function crypto_sign_open($signedMessage, $pk)
{
try {
return ParagonIE_Sodium_Compat::crypto_sign_open($signedMessage, $pk);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_sign_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_publickey(
#[\SensitiveParameter]
$keypair
) {
return ParagonIE_Sodium_Compat::crypto_sign_publickey($keypair);
}
}
if (!is_callable('\\Sodium\\crypto_sign_publickey_from_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey()
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_publickey_from_secretkey(
#[\SensitiveParameter]
$sk
) {
return ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey($sk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_secretkey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_secretkey(
#[\SensitiveParameter]
$keypair
) {
return ParagonIE_Sodium_Compat::crypto_sign_secretkey($keypair);
}
}
if (!is_callable('\\Sodium\\crypto_sign_seed_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_seed_keypair()
* @param string $seed
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_seed_keypair(
#[\SensitiveParameter]
$seed
) {
return ParagonIE_Sodium_Compat::crypto_sign_seed_keypair($seed);
}
}
if (!is_callable('\\Sodium\\crypto_sign_verify_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_verify_detached()
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_verify_detached($signature, $message, $pk)
{
return ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $message, $pk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519()
* @param string $pk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_ed25519_pk_to_curve25519($pk)
{
return ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519($pk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519()
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_ed25519_sk_to_curve25519(
#[\SensitiveParameter]
$sk
) {
return ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519($sk);
}
}
if (!is_callable('\\Sodium\\crypto_stream')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream()
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_stream(
$len,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream($len, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_stream_xor')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xor()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_stream_xor(
#[\SensitiveParameter]
$message,
$nonce,
#[\SensitiveParameter]
$key
) {
return ParagonIE_Sodium_Compat::crypto_stream_xor($message, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\hex2bin')) {
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function hex2bin(
#[\SensitiveParameter]
$string
) {
return ParagonIE_Sodium_Compat::hex2bin($string);
}
}
if (!is_callable('\\Sodium\\memcmp')) {
/**
* @see ParagonIE_Sodium_Compat::memcmp()
* @param string $a
* @param string $b
* @return int
* @throws \SodiumException
* @throws \TypeError
*/
function memcmp(
#[\SensitiveParameter]
$a,
#[\SensitiveParameter]
$b
) {
return ParagonIE_Sodium_Compat::memcmp($a, $b);
}
}
if (!is_callable('\\Sodium\\memzero')) {
/**
* @see ParagonIE_Sodium_Compat::memzero()
* @param string $str
* @return void
* @throws \SodiumException
* @throws \TypeError
*
* @psalm-suppress MissingParamType
* @psalm-suppress MissingReturnType
* @psalm-suppress ReferenceConstraintViolation
*/
function memzero(
#[\SensitiveParameter]
&$str
) {
ParagonIE_Sodium_Compat::memzero($str);
}
}
if (!is_callable('\\Sodium\\randombytes_buf')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_buf()
* @param int $amount
* @return string
* @throws \TypeError
*/
function randombytes_buf($amount)
{
return ParagonIE_Sodium_Compat::randombytes_buf($amount);
}
}
if (!is_callable('\\Sodium\\randombytes_uniform')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_uniform()
* @param int $upperLimit
* @return int
* @throws \SodiumException
* @throws \Error
*/
function randombytes_uniform($upperLimit)
{
return ParagonIE_Sodium_Compat::randombytes_uniform($upperLimit);
}
}
if (!is_callable('\\Sodium\\randombytes_random16')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_random16()
* @return int
*/
function randombytes_random16()
{
return ParagonIE_Sodium_Compat::randombytes_random16();
}
}
if (!defined('\\Sodium\\CRYPTO_AUTH_BYTES')) {
require_once dirname(__FILE__) . '/constants.php';
}
<?php
const SODIUM_LIBRARY_MAJOR_VERSION = 9;
const SODIUM_LIBRARY_MINOR_VERSION = 1;
const SODIUM_LIBRARY_VERSION = '1.0.8';
const SODIUM_BASE64_VARIANT_ORIGINAL = 1;
const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
const SODIUM_BASE64_VARIANT_URLSAFE = 5;
const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
const SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
const SODIUM_CRYPTO_AEAD_AES256GCM_ABYTES = 16;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
const SODIUM_CRYPTO_AUTH_BYTES = 32;
const SODIUM_CRYPTO_AUTH_KEYBYTES = 32;
const SODIUM_CRYPTO_BOX_SEALBYTES = 16;
const SODIUM_CRYPTO_BOX_SECRETKEYBYTES = 32;
const SODIUM_CRYPTO_BOX_PUBLICKEYBYTES = 32;
const SODIUM_CRYPTO_BOX_KEYPAIRBYTES = 64;
const SODIUM_CRYPTO_BOX_MACBYTES = 16;
const SODIUM_CRYPTO_BOX_NONCEBYTES = 24;
const SODIUM_CRYPTO_BOX_SEEDBYTES = 32;
const SODIUM_CRYPTO_KDF_BYTES_MIN = 16;
const SODIUM_CRYPTO_KDF_BYTES_MAX = 64;
const SODIUM_CRYPTO_KDF_CONTEXTBYTES = 8;
const SODIUM_CRYPTO_KDF_KEYBYTES = 32;
const SODIUM_CRYPTO_KX_BYTES = 32;
const SODIUM_CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
const SODIUM_CRYPTO_KX_SEEDBYTES = 32;
const SODIUM_CRYPTO_KX_KEYPAIRBYTES = 64;
const SODIUM_CRYPTO_KX_PUBLICKEYBYTES = 32;
const SODIUM_CRYPTO_KX_SECRETKEYBYTES = 32;
const SODIUM_CRYPTO_KX_SESSIONKEYBYTES = 32;
const SODIUM_CRYPTO_GENERICHASH_BYTES = 32;
const SODIUM_CRYPTO_GENERICHASH_BYTES_MIN = 16;
const SODIUM_CRYPTO_GENERICHASH_BYTES_MAX = 64;
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES = 32;
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
const SODIUM_CRYPTO_PWHASH_SALTBYTES = 16;
const SODIUM_CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
const SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
const SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$';
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824;
const SODIUM_CRYPTO_SCALARMULT_BYTES = 32;
const SODIUM_CRYPTO_SCALARMULT_SCALARBYTES = 32;
const SODIUM_CRYPTO_SHORTHASH_BYTES = 8;
const SODIUM_CRYPTO_SHORTHASH_KEYBYTES = 16;
const SODIUM_CRYPTO_SECRETBOX_KEYBYTES = 32;
const SODIUM_CRYPTO_SECRETBOX_MACBYTES = 16;
const SODIUM_CRYPTO_SECRETBOX_NONCEBYTES = 24;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
const SODIUM_CRYPTO_SIGN_BYTES = 64;
const SODIUM_CRYPTO_SIGN_SEEDBYTES = 32;
const SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES = 32;
const SODIUM_CRYPTO_SIGN_SECRETKEYBYTES = 64;
const SODIUM_CRYPTO_SIGN_KEYPAIRBYTES = 96;
const SODIUM_CRYPTO_STREAM_KEYBYTES = 32;
const SODIUM_CRYPTO_STREAM_NONCEBYTES = 24;
const SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32;
const SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24;
<?php
const SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES = 16;
const SODIUM_CRYPTO_AEAD_AEGIS128L_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_AEGIS128L_NPUBBYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS128L_ABYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS256_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS256_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_AEGIS256_NPUBBYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS256_ABYTES = 32;
<?php
require_once dirname(dirname(__FILE__)) . '/autoload.php';
if (PHP_VERSION_ID < 50300) {
return;
}
/*
* This file is just for convenience, to allow developers to reduce verbosity when
* they add this project to their libraries.
*
* Replace this:
*
* $x = ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_encrypt(...$args);
*
* with this:
*
* use ParagonIE\Sodium\Compat;
*
* $x = Compat::crypto_aead_xchacha20poly1305_encrypt(...$args);
*/
spl_autoload_register(function ($class) {
if ($class[0] === '\\') {
$class = substr($class, 1);
}
$namespace = 'ParagonIE\\Sodium';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = dirname(dirname(__FILE__)) . '/namespaced/' . str_replace('\\', '/', $relative_class) . '.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
});
{
"name": "paragonie/sodium_compat",
"description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists",
"keywords": [
"PHP",
"cryptography",
"elliptic curve",
"elliptic curve cryptography",
"Pure-PHP cryptography",
"side-channel resistant",
"Curve25519",
"X25519",
"ECDH",
"Elliptic Curve Diffie-Hellman",
"Ed25519",
"RFC 7748",
"RFC 8032",
"EdDSA",
"Edwards-curve Digital Signature Algorithm",
"ChaCha20",
"Salsa20",
"Xchacha20",
"Xsalsa20",
"Poly1305",
"BLAKE2b",
"public-key cryptography",
"secret-key cryptography",
"AEAD",
"Chapoly",
"Salpoly",
"ChaCha20-Poly1305",
"XSalsa20-Poly1305",
"XChaCha20-Poly1305",
"encryption",
"authentication",
"libsodium"
],
"license": "ISC",
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com"
},
{
"name": "Frank Denis",
"email": "jedisct1@pureftpd.org"
}
],
"autoload": {
"files": ["autoload.php"]
},
"require": {
"php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8",
"paragonie/random_compat": ">=1"
},
"require-dev": {
"phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9"
},
"scripts": {
"test": "phpunit"
},
"suggest": {
"ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.",
"ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
}
}
ISC License
Copyright (c) 2016-2023, Paragon Initiative Enterprises <security at paragonie dot com>
Copyright (c) 2013-2019, Frank Denis <j at pureftpd dot org>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
[02-Dec-2025 10:43:36 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_HTML_Tag_Processor" not found in /home/coopserp/public_html/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php:18
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php on line 18
<?php
/**
* Interactivity API: WP_Interactivity_API class.
*
* @package WordPress
* @subpackage Interactivity API
* @since 6.5.0
*/
/**
* Class used to process the Interactivity API on the server.
*
* @since 6.5.0
*/
final class WP_Interactivity_API {
/**
* Holds the mapping of directive attribute names to their processor methods.
*
* @since 6.5.0
* @var array
*/
private static $directive_processors = array(
'data-wp-interactive' => 'data_wp_interactive_processor',
'data-wp-router-region' => 'data_wp_router_region_processor',
'data-wp-context' => 'data_wp_context_processor',
'data-wp-bind' => 'data_wp_bind_processor',
'data-wp-class' => 'data_wp_class_processor',
'data-wp-style' => 'data_wp_style_processor',
'data-wp-text' => 'data_wp_text_processor',
/*
* `data-wp-each` needs to be processed in the last place because it moves
* the cursor to the end of the processed items to prevent them to be
* processed twice.
*/
'data-wp-each' => 'data_wp_each_processor',
);
/**
* Holds the initial state of the different Interactivity API stores.
*
* This state is used during the server directive processing. Then, it is
* serialized and sent to the client as part of the interactivity data to be
* recovered during the hydration of the client interactivity stores.
*
* @since 6.5.0
* @var array
*/
private $state_data = array();
/**
* Holds the configuration required by the different Interactivity API stores.
*
* This configuration is serialized and sent to the client as part of the
* interactivity data and can be accessed by the client interactivity stores.
*
* @since 6.5.0
* @var array
*/
private $config_data = array();
/**
* Flag that indicates whether the `data-wp-router-region` directive has
* been found in the HTML and processed.
*
* The value is saved in a private property of the WP_Interactivity_API
* instance instead of using a static variable inside the processor
* function, which would hold the same value for all instances
* independently of whether they have processed any
* `data-wp-router-region` directive or not.
*
* @since 6.5.0
* @var bool
*/
private $has_processed_router_region = false;
/**
* Stack of namespaces defined by `data-wp-interactive` directives, in
* the order they are processed.
*
* This is only available during directive processing, otherwise it is `null`.
*
* @since 6.6.0
* @var array<string>|null
*/
private $namespace_stack = null;
/**
* Stack of contexts defined by `data-wp-context` directives, in
* the order they are processed.
*
* This is only available during directive processing, otherwise it is `null`.
*
* @since 6.6.0
* @var array<array<mixed>>|null
*/
private $context_stack = null;
/**
* Representation in array format of the element currently being processed.
*
* This is only available during directive processing, otherwise it is `null`.
*
* @since 6.7.0
* @var array{attributes: array<string, string|bool>}|null
*/
private $current_element = null;
/**
* Gets and/or sets the initial state of an Interactivity API store for a
* given namespace.
*
* If state for that store namespace already exists, it merges the new
* provided state with the existing one.
*
* When no namespace is specified, it returns the state defined for the
* current value in the internal namespace stack during a `process_directives` call.
*
* @since 6.5.0
* @since 6.6.0 The `$store_namespace` param is optional.
*
* @param string $store_namespace Optional. The unique store namespace identifier.
* @param array $state Optional. The array that will be merged with the existing state for the specified
* store namespace.
* @return array The current state for the specified store namespace. This will be the updated state if a $state
* argument was provided.
*/
public function state( ?string $store_namespace = null, ?array $state = null ): array {
if ( ! $store_namespace ) {
if ( $state ) {
_doing_it_wrong(
__METHOD__,
__( 'The namespace is required when state data is passed.' ),
'6.6.0'
);
return array();
}
if ( null !== $store_namespace ) {
_doing_it_wrong(
__METHOD__,
__( 'The namespace should be a non-empty string.' ),
'6.6.0'
);
return array();
}
if ( null === $this->namespace_stack ) {
_doing_it_wrong(
__METHOD__,
__( 'The namespace can only be omitted during directive processing.' ),
'6.6.0'
);
return array();
}
$store_namespace = end( $this->namespace_stack );
}
if ( ! isset( $this->state_data[ $store_namespace ] ) ) {
$this->state_data[ $store_namespace ] = array();
}
if ( is_array( $state ) ) {
$this->state_data[ $store_namespace ] = array_replace_recursive(
$this->state_data[ $store_namespace ],
$state
);
}
return $this->state_data[ $store_namespace ];
}
/**
* Gets and/or sets the configuration of the Interactivity API for a given
* store namespace.
*
* If configuration for that store namespace exists, it merges the new
* provided configuration with the existing one.
*
* @since 6.5.0
*
* @param string $store_namespace The unique store namespace identifier.
* @param array $config Optional. The array that will be merged with the existing configuration for the
* specified store namespace.
* @return array The configuration for the specified store namespace. This will be the updated configuration if a
* $config argument was provided.
*/
public function config( string $store_namespace, array $config = array() ): array {
if ( ! isset( $this->config_data[ $store_namespace ] ) ) {
$this->config_data[ $store_namespace ] = array();
}
if ( is_array( $config ) ) {
$this->config_data[ $store_namespace ] = array_replace_recursive(
$this->config_data[ $store_namespace ],
$config
);
}
return $this->config_data[ $store_namespace ];
}
/**
* Prints the serialized client-side interactivity data.
*
* Encodes the config and initial state into JSON and prints them inside a
* script tag of type "application/json". Once in the browser, the state will
* be parsed and used to hydrate the client-side interactivity stores and the
* configuration will be available using a `getConfig` utility.
*
* @since 6.5.0
*
* @deprecated 6.7.0 Client data passing is handled by the {@see "script_module_data_{$module_id}"} filter.
*/
public function print_client_interactivity_data() {
_deprecated_function( __METHOD__, '6.7.0' );
}
/**
* Set client-side interactivity-router data.
*
* Once in the browser, the state will be parsed and used to hydrate the client-side
* interactivity stores and the configuration will be available using a `getConfig` utility.
*
* @since 6.7.0
*
* @param array $data Data to filter.
* @return array Data for the Interactivity Router script module.
*/
public function filter_script_module_interactivity_router_data( array $data ): array {
if ( ! isset( $data['i18n'] ) ) {
$data['i18n'] = array();
}
$data['i18n']['loading'] = __( 'Loading page, please wait.' );
$data['i18n']['loaded'] = __( 'Page Loaded.' );
return $data;
}
/**
* Set client-side interactivity data.
*
* Once in the browser, the state will be parsed and used to hydrate the client-side
* interactivity stores and the configuration will be available using a `getConfig` utility.
*
* @since 6.7.0
*
* @param array $data Data to filter.
* @return array Data for the Interactivity API script module.
*/
public function filter_script_module_interactivity_data( array $data ): array {
if ( empty( $this->state_data ) && empty( $this->config_data ) ) {
return $data;
}
$config = array();
foreach ( $this->config_data as $key => $value ) {
if ( ! empty( $value ) ) {
$config[ $key ] = $value;
}
}
if ( ! empty( $config ) ) {
$data['config'] = $config;
}
$state = array();
foreach ( $this->state_data as $key => $value ) {
if ( ! empty( $value ) ) {
$state[ $key ] = $value;
}
}
if ( ! empty( $state ) ) {
$data['state'] = $state;
}
return $data;
}
/**
* Returns the latest value on the context stack with the passed namespace.
*
* When the namespace is omitted, it uses the current namespace on the
* namespace stack during a `process_directives` call.
*
* @since 6.6.0
*
* @param string $store_namespace Optional. The unique store namespace identifier.
*/
public function get_context( ?string $store_namespace = null ): array {
if ( null === $this->context_stack ) {
_doing_it_wrong(
__METHOD__,
__( 'The context can only be read during directive processing.' ),
'6.6.0'
);
return array();
}
if ( ! $store_namespace ) {
if ( null !== $store_namespace ) {
_doing_it_wrong(
__METHOD__,
__( 'The namespace should be a non-empty string.' ),
'6.6.0'
);
return array();
}
$store_namespace = end( $this->namespace_stack );
}
$context = end( $this->context_stack );
return ( $store_namespace && $context && isset( $context[ $store_namespace ] ) )
? $context[ $store_namespace ]
: array();
}
/**
* Returns an array representation of the current element being processed.
*
* The returned array contains a copy of the element attributes.
*
* @since 6.7.0
*
* @return array{attributes: array<string, string|bool>}|null Current element.
*/
public function get_element(): ?array {
if ( null === $this->current_element ) {
_doing_it_wrong(
__METHOD__,
__( 'The element can only be read during directive processing.' ),
'6.7.0'
);
}
return $this->current_element;
}
/**
* Registers the `@wordpress/interactivity` script modules.
*
* @deprecated 6.7.0 Script Modules registration is handled by {@see wp_default_script_modules()}.
*
* @since 6.5.0
*/
public function register_script_modules() {
_deprecated_function( __METHOD__, '6.7.0', 'wp_default_script_modules' );
}
/**
* Adds the necessary hooks for the Interactivity API.
*
* @since 6.5.0
*/
public function add_hooks() {
add_filter( 'script_module_data_@wordpress/interactivity', array( $this, 'filter_script_module_interactivity_data' ) );
add_filter( 'script_module_data_@wordpress/interactivity-router', array( $this, 'filter_script_module_interactivity_router_data' ) );
}
/**
* Processes the interactivity directives contained within the HTML content
* and updates the markup accordingly.
*
* @since 6.5.0
*
* @param string $html The HTML content to process.
* @return string The processed HTML content. It returns the original content when the HTML contains unbalanced tags.
*/
public function process_directives( string $html ): string {
if ( ! str_contains( $html, 'data-wp-' ) ) {
return $html;
}
$this->namespace_stack = array();
$this->context_stack = array();
$result = $this->_process_directives( $html );
$this->namespace_stack = null;
$this->context_stack = null;
return null === $result ? $html : $result;
}
/**
* Processes the interactivity directives contained within the HTML content
* and updates the markup accordingly.
*
* It uses the WP_Interactivity_API instance's context and namespace stacks,
* which are shared between all calls.
*
* This method returns null if the HTML contains unbalanced tags.
*
* @since 6.6.0
*
* @param string $html The HTML content to process.
* @return string|null The processed HTML content. It returns null when the HTML contains unbalanced tags.
*/
private function _process_directives( string $html ) {
$p = new WP_Interactivity_API_Directives_Processor( $html );
$tag_stack = array();
$unbalanced = false;
$directive_processor_prefixes = array_keys( self::$directive_processors );
$directive_processor_prefixes_reversed = array_reverse( $directive_processor_prefixes );
/*
* Save the current size for each stack to restore them in case
* the processing finds unbalanced tags.
*/
$namespace_stack_size = count( $this->namespace_stack );
$context_stack_size = count( $this->context_stack );
while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) {
$tag_name = $p->get_tag();
/*
* Directives inside SVG and MATH tags are not processed,
* as they are not compatible with the Tag Processor yet.
* We still process the rest of the HTML.
*/
if ( 'SVG' === $tag_name || 'MATH' === $tag_name ) {
if ( $p->get_attribute_names_with_prefix( 'data-wp-' ) ) {
/* translators: 1: SVG or MATH HTML tag, 2: Namespace of the interactive block. */
$message = sprintf( __( 'Interactivity directives were detected on an incompatible %1$s tag when processing "%2$s". These directives will be ignored in the server side render.' ), $tag_name, end( $this->namespace_stack ) );
_doing_it_wrong( __METHOD__, $message, '6.6.0' );
}
$p->skip_to_tag_closer();
continue;
}
if ( $p->is_tag_closer() ) {
list( $opening_tag_name, $directives_prefixes ) = end( $tag_stack );
if ( 0 === count( $tag_stack ) || $opening_tag_name !== $tag_name ) {
/*
* If the tag stack is empty or the matching opening tag is not the
* same than the closing tag, it means the HTML is unbalanced and it
* stops processing it.
*/
$unbalanced = true;
break;
} else {
// Remove the last tag from the stack.
array_pop( $tag_stack );
}
} else {
if ( 0 !== count( $p->get_attribute_names_with_prefix( 'data-wp-each-child' ) ) ) {
/*
* If the tag has a `data-wp-each-child` directive, jump to its closer
* tag because those tags have already been processed.
*/
$p->next_balanced_tag_closer_tag();
continue;
} else {
$directives_prefixes = array();
// Checks if there is a server directive processor registered for each directive.
foreach ( $p->get_attribute_names_with_prefix( 'data-wp-' ) as $attribute_name ) {
if ( ! preg_match(
/*
* This must align with the client-side regex used by the interactivity API.
* @see https://github.com/WordPress/gutenberg/blob/ca616014255efbb61f34c10917d52a2d86c1c660/packages/interactivity/src/vdom.ts#L20-L32
*/
'/' .
'^data-wp-' .
// Match alphanumeric characters including hyphen-separated
// segments. It excludes underscore intentionally to prevent confusion.
// E.g., "custom-directive".
'([a-z0-9]+(?:-[a-z0-9]+)*)' .
// (Optional) Match '--' followed by any alphanumeric charachters. It
// excludes underscore intentionally to prevent confusion, but it can
// contain multiple hyphens. E.g., "--custom-prefix--with-more-info".
'(?:--([a-z0-9_-]+))?$' .
'/i',
$attribute_name
) ) {
continue;
}
list( $directive_prefix ) = $this->extract_prefix_and_suffix( $attribute_name );
if ( array_key_exists( $directive_prefix, self::$directive_processors ) ) {
$directives_prefixes[] = $directive_prefix;
}
}
/*
* If this tag will visit its closer tag, it adds it to the tag stack
* so it can process its closing tag and check for unbalanced tags.
*/
if ( $p->has_and_visits_its_closer_tag() ) {
$tag_stack[] = array( $tag_name, $directives_prefixes );
}
}
}
/*
* If the matching opener tag didn't have any directives, it can skip the
* processing.
*/
if ( 0 === count( $directives_prefixes ) ) {
continue;
}
// Directive processing might be different depending on if it is entering the tag or exiting it.
$modes = array(
'enter' => ! $p->is_tag_closer(),
'exit' => $p->is_tag_closer() || ! $p->has_and_visits_its_closer_tag(),
);
// Get the element attributes to include them in the element representation.
$element_attrs = array();
$attr_names = $p->get_attribute_names_with_prefix( '' ) ?? array();
foreach ( $attr_names as $name ) {
$element_attrs[ $name ] = $p->get_attribute( $name );
}
// Assign the current element right before running its directive processors.
$this->current_element = array(
'attributes' => $element_attrs,
);
foreach ( $modes as $mode => $should_run ) {
if ( ! $should_run ) {
continue;
}
/*
* Sorts the attributes by the order of the `directives_processor` array
* and checks what directives are present in this element.
*/
$existing_directives_prefixes = array_intersect(
'enter' === $mode ? $directive_processor_prefixes : $directive_processor_prefixes_reversed,
$directives_prefixes
);
foreach ( $existing_directives_prefixes as $directive_prefix ) {
$func = is_array( self::$directive_processors[ $directive_prefix ] )
? self::$directive_processors[ $directive_prefix ]
: array( $this, self::$directive_processors[ $directive_prefix ] );
call_user_func_array( $func, array( $p, $mode, &$tag_stack ) );
}
}
// Clear the current element.
$this->current_element = null;
}
if ( $unbalanced ) {
// Reset the namespace and context stacks to their previous values.
array_splice( $this->namespace_stack, $namespace_stack_size );
array_splice( $this->context_stack, $context_stack_size );
}
/*
* It returns null if the HTML is unbalanced because unbalanced HTML is
* not safe to process. In that case, the Interactivity API runtime will
* update the HTML on the client side during the hydration. It will also
* display a notice to the developer to inform them about the issue.
*/
if ( $unbalanced || 0 < count( $tag_stack ) ) {
$tag_errored = 0 < count( $tag_stack ) ? end( $tag_stack )[0] : $tag_name;
/* translators: %1s: Namespace processed, %2s: The tag that caused the error; could be any HTML tag. */
$message = sprintf( __( 'Interactivity directives failed to process in "%1$s" due to a missing "%2$s" end tag.' ), end( $this->namespace_stack ), $tag_errored );
_doing_it_wrong( __METHOD__, $message, '6.6.0' );
return null;
}
return $p->get_updated_html();
}
/**
* Evaluates the reference path passed to a directive based on the current
* store namespace, state and context.
*
* @since 6.5.0
* @since 6.6.0 The function now adds a warning when the namespace is null, falsy, or the directive value is empty.
* @since 6.6.0 Removed `default_namespace` and `context` arguments.
* @since 6.6.0 Add support for derived state.
*
* @param string|true $directive_value The directive attribute value string or `true` when it's a boolean attribute.
* @return mixed|null The result of the evaluation. Null if the reference path doesn't exist or the namespace is falsy.
*/
private function evaluate( $directive_value ) {
$default_namespace = end( $this->namespace_stack );
$context = end( $this->context_stack );
list( $ns, $path ) = $this->extract_directive_value( $directive_value, $default_namespace );
if ( ! $ns || ! $path ) {
/* translators: %s: The directive value referenced. */
$message = sprintf( __( 'Namespace or reference path cannot be empty. Directive value referenced: %s' ), $directive_value );
_doing_it_wrong( __METHOD__, $message, '6.6.0' );
return null;
}
$store = array(
'state' => $this->state_data[ $ns ] ?? array(),
'context' => $context[ $ns ] ?? array(),
);
// Checks if the reference path is preceded by a negation operator (!).
$should_negate_value = '!' === $path[0];
$path = $should_negate_value ? substr( $path, 1 ) : $path;
// Extracts the value from the store using the reference path.
$path_segments = explode( '.', $path );
$current = $store;
foreach ( $path_segments as $path_segment ) {
/*
* Special case for numeric arrays and strings. Add length
* property mimicking JavaScript behavior.
*
* @since 6.8.0
*/
if ( 'length' === $path_segment ) {
if ( is_array( $current ) && array_is_list( $current ) ) {
$current = count( $current );
break;
}
if ( is_string( $current ) ) {
/*
* Differences in encoding between PHP strings and
* JavaScript mean that it's complicated to calculate
* the string length JavaScript would see from PHP.
* `strlen` is a reasonable approximation.
*
* Users that desire a more precise length likely have
* more precise needs than "bytelength" and should
* implement their own length calculation in derived
* state taking into account encoding and their desired
* output (codepoints, graphemes, bytes, etc.).
*/
$current = strlen( $current );
break;
}
}
if ( ( is_array( $current ) || $current instanceof ArrayAccess ) && isset( $current[ $path_segment ] ) ) {
$current = $current[ $path_segment ];
} elseif ( is_object( $current ) && isset( $current->$path_segment ) ) {
$current = $current->$path_segment;
} else {
$current = null;
break;
}
if ( $current instanceof Closure ) {
/*
* This state getter's namespace is added to the stack so that
* `state()` or `get_config()` read that namespace when called
* without specifying one.
*/
array_push( $this->namespace_stack, $ns );
try {
$current = $current();
} catch ( Throwable $e ) {
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: 1: Path pointing to an Interactivity API state property, 2: Namespace for an Interactivity API store. */
__( 'Uncaught error executing a derived state callback with path "%1$s" and namespace "%2$s".' ),
$path,
$ns
),
'6.6.0'
);
return null;
} finally {
// Remove the property's namespace from the stack.
array_pop( $this->namespace_stack );
}
}
}
// Returns the opposite if it contains a negation operator (!).
return $should_negate_value ? ! $current : $current;
}
/**
* Extracts the directive attribute name to separate and return the directive
* prefix and an optional suffix.
*
* The suffix is the string after the first double hyphen and the prefix is
* everything that comes before the suffix.
*
* Example:
*
* extract_prefix_and_suffix( 'data-wp-interactive' ) => array( 'data-wp-interactive', null )
* extract_prefix_and_suffix( 'data-wp-bind--src' ) => array( 'data-wp-bind', 'src' )
* extract_prefix_and_suffix( 'data-wp-foo--and--bar' ) => array( 'data-wp-foo', 'and--bar' )
*
* @since 6.5.0
*
* @param string $directive_name The directive attribute name.
* @return array An array containing the directive prefix and optional suffix.
*/
private function extract_prefix_and_suffix( string $directive_name ): array {
return explode( '--', $directive_name, 2 );
}
/**
* Parses and extracts the namespace and reference path from the given
* directive attribute value.
*
* If the value doesn't contain an explicit namespace, it returns the
* default one. If the value contains a JSON object instead of a reference
* path, the function tries to parse it and return the resulting array. If
* the value contains strings that represent booleans ("true" and "false"),
* numbers ("1" and "1.2") or "null", the function also transform them to
* regular booleans, numbers and `null`.
*
* Example:
*
* extract_directive_value( 'actions.foo', 'myPlugin' ) => array( 'myPlugin', 'actions.foo' )
* extract_directive_value( 'otherPlugin::actions.foo', 'myPlugin' ) => array( 'otherPlugin', 'actions.foo' )
* extract_directive_value( '{ "isOpen": false }', 'myPlugin' ) => array( 'myPlugin', array( 'isOpen' => false ) )
* extract_directive_value( 'otherPlugin::{ "isOpen": false }', 'myPlugin' ) => array( 'otherPlugin', array( 'isOpen' => false ) )
*
* @since 6.5.0
*
* @param string|true $directive_value The directive attribute value. It can be `true` when it's a boolean
* attribute.
* @param string|null $default_namespace Optional. The default namespace if none is explicitly defined.
* @return array An array containing the namespace in the first item and the JSON, the reference path, or null on the
* second item.
*/
private function extract_directive_value( $directive_value, $default_namespace = null ): array {
if ( empty( $directive_value ) || is_bool( $directive_value ) ) {
return array( $default_namespace, null );
}
// Replaces the value and namespace if there is a namespace in the value.
if ( 1 === preg_match( '/^([\w\-_\/]+)::./', $directive_value ) ) {
list($default_namespace, $directive_value) = explode( '::', $directive_value, 2 );
}
/*
* Tries to decode the value as a JSON object. If it fails and the value
* isn't `null`, it returns the value as it is. Otherwise, it returns the
* decoded JSON or null for the string `null`.
*/
$decoded_json = json_decode( $directive_value, true );
if ( null !== $decoded_json || 'null' === $directive_value ) {
$directive_value = $decoded_json;
}
return array( $default_namespace, $directive_value );
}
/**
* Transforms a kebab-case string to camelCase.
*
* @param string $str The kebab-case string to transform to camelCase.
* @return string The transformed camelCase string.
*/
private function kebab_to_camel_case( string $str ): string {
return lcfirst(
preg_replace_callback(
'/(-)([a-z])/',
function ( $matches ) {
return strtoupper( $matches[2] );
},
strtolower( rtrim( $str, '-' ) )
)
);
}
/**
* Processes the `data-wp-interactive` directive.
*
* It adds the default store namespace defined in the directive value to the
* stack so that it's available for the nested interactivity elements.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_interactive_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
// When exiting tags, it removes the last namespace from the stack.
if ( 'exit' === $mode ) {
array_pop( $this->namespace_stack );
return;
}
// Tries to decode the `data-wp-interactive` attribute value.
$attribute_value = $p->get_attribute( 'data-wp-interactive' );
/*
* Pushes the newly defined namespace or the current one if the
* `data-wp-interactive` definition was invalid or does not contain a
* namespace. It does so because the function pops out the current namespace
* from the stack whenever it finds a `data-wp-interactive`'s closing tag,
* independently of whether the previous `data-wp-interactive` definition
* contained a valid namespace.
*/
$new_namespace = null;
if ( is_string( $attribute_value ) && ! empty( $attribute_value ) ) {
$decoded_json = json_decode( $attribute_value, true );
if ( is_array( $decoded_json ) ) {
$new_namespace = $decoded_json['namespace'] ?? null;
} else {
$new_namespace = $attribute_value;
}
}
$this->namespace_stack[] = ( $new_namespace && 1 === preg_match( '/^([\w\-_\/]+)/', $new_namespace ) )
? $new_namespace
: end( $this->namespace_stack );
}
/**
* Processes the `data-wp-context` directive.
*
* It adds the context defined in the directive value to the stack so that
* it's available for the nested interactivity elements.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_context_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
// When exiting tags, it removes the last context from the stack.
if ( 'exit' === $mode ) {
array_pop( $this->context_stack );
return;
}
$attribute_value = $p->get_attribute( 'data-wp-context' );
$namespace_value = end( $this->namespace_stack );
// Separates the namespace from the context JSON object.
list( $namespace_value, $decoded_json ) = is_string( $attribute_value ) && ! empty( $attribute_value )
? $this->extract_directive_value( $attribute_value, $namespace_value )
: array( $namespace_value, null );
/*
* If there is a namespace, it adds a new context to the stack merging the
* previous context with the new one.
*/
if ( is_string( $namespace_value ) ) {
$this->context_stack[] = array_replace_recursive(
end( $this->context_stack ) !== false ? end( $this->context_stack ) : array(),
array( $namespace_value => is_array( $decoded_json ) ? $decoded_json : array() )
);
} else {
/*
* If there is no namespace, it pushes the current context to the stack.
* It needs to do so because the function pops out the current context
* from the stack whenever it finds a `data-wp-context`'s closing tag.
*/
$this->context_stack[] = end( $this->context_stack );
}
}
/**
* Processes the `data-wp-bind` directive.
*
* It updates or removes the bound attributes based on the evaluation of its
* associated reference.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
if ( 'enter' === $mode ) {
$all_bind_directives = $p->get_attribute_names_with_prefix( 'data-wp-bind--' );
foreach ( $all_bind_directives as $attribute_name ) {
list( , $bound_attribute ) = $this->extract_prefix_and_suffix( $attribute_name );
if ( empty( $bound_attribute ) ) {
return;
}
$attribute_value = $p->get_attribute( $attribute_name );
$result = $this->evaluate( $attribute_value );
if (
null !== $result &&
(
false !== $result ||
( strlen( $bound_attribute ) > 5 && '-' === $bound_attribute[4] )
)
) {
/*
* If the result of the evaluation is a boolean and the attribute is
* `aria-` or `data-, convert it to a string "true" or "false". It
* follows the exact same logic as Preact because it needs to
* replicate what Preact will later do in the client:
* https://github.com/preactjs/preact/blob/ea49f7a0f9d1ff2c98c0bdd66aa0cbc583055246/src/diff/props.js#L131C24-L136
*/
if (
is_bool( $result ) &&
( strlen( $bound_attribute ) > 5 && '-' === $bound_attribute[4] )
) {
$result = $result ? 'true' : 'false';
}
$p->set_attribute( $bound_attribute, $result );
} else {
$p->remove_attribute( $bound_attribute );
}
}
}
}
/**
* Processes the `data-wp-class` directive.
*
* It adds or removes CSS classes in the current HTML element based on the
* evaluation of its associated references.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_class_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
if ( 'enter' === $mode ) {
$all_class_directives = $p->get_attribute_names_with_prefix( 'data-wp-class--' );
foreach ( $all_class_directives as $attribute_name ) {
list( , $class_name ) = $this->extract_prefix_and_suffix( $attribute_name );
if ( empty( $class_name ) ) {
return;
}
$attribute_value = $p->get_attribute( $attribute_name );
$result = $this->evaluate( $attribute_value );
if ( $result ) {
$p->add_class( $class_name );
} else {
$p->remove_class( $class_name );
}
}
}
}
/**
* Processes the `data-wp-style` directive.
*
* It updates the style attribute value of the current HTML element based on
* the evaluation of its associated references.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
if ( 'enter' === $mode ) {
$all_style_attributes = $p->get_attribute_names_with_prefix( 'data-wp-style--' );
foreach ( $all_style_attributes as $attribute_name ) {
list( , $style_property ) = $this->extract_prefix_and_suffix( $attribute_name );
if ( empty( $style_property ) ) {
continue;
}
$directive_attribute_value = $p->get_attribute( $attribute_name );
$style_property_value = $this->evaluate( $directive_attribute_value );
$style_attribute_value = $p->get_attribute( 'style' );
$style_attribute_value = ( $style_attribute_value && ! is_bool( $style_attribute_value ) ) ? $style_attribute_value : '';
/*
* Checks first if the style property is not falsy and the style
* attribute value is not empty because if it is, it doesn't need to
* update the attribute value.
*/
if ( $style_property_value || $style_attribute_value ) {
$style_attribute_value = $this->merge_style_property( $style_attribute_value, $style_property, $style_property_value );
/*
* If the style attribute value is not empty, it sets it. Otherwise,
* it removes it.
*/
if ( ! empty( $style_attribute_value ) ) {
$p->set_attribute( 'style', $style_attribute_value );
} else {
$p->remove_attribute( 'style' );
}
}
}
}
}
/**
* Merges an individual style property in the `style` attribute of an HTML
* element, updating or removing the property when necessary.
*
* If a property is modified, the old one is removed and the new one is added
* at the end of the list.
*
* @since 6.5.0
*
* Example:
*
* merge_style_property( 'color:green;', 'color', 'red' ) => 'color:red;'
* merge_style_property( 'background:green;', 'color', 'red' ) => 'background:green;color:red;'
* merge_style_property( 'color:green;', 'color', null ) => ''
*
* @param string $style_attribute_value The current style attribute value.
* @param string $style_property_name The style property name to set.
* @param string|false|null $style_property_value The value to set for the style property. With false, null or an
* empty string, it removes the style property.
* @return string The new style attribute value after the specified property has been added, updated or removed.
*/
private function merge_style_property( string $style_attribute_value, string $style_property_name, $style_property_value ): string {
$style_assignments = explode( ';', $style_attribute_value );
$result = array();
$style_property_value = ! empty( $style_property_value ) ? rtrim( trim( $style_property_value ), ';' ) : null;
$new_style_property = $style_property_value ? $style_property_name . ':' . $style_property_value . ';' : '';
// Generates an array with all the properties but the modified one.
foreach ( $style_assignments as $style_assignment ) {
if ( empty( trim( $style_assignment ) ) ) {
continue;
}
list( $name, $value ) = explode( ':', $style_assignment );
if ( trim( $name ) !== $style_property_name ) {
$result[] = trim( $name ) . ':' . trim( $value ) . ';';
}
}
// Adds the new/modified property at the end of the list.
$result[] = $new_style_property;
return implode( '', $result );
}
/**
* Processes the `data-wp-text` directive.
*
* It updates the inner content of the current HTML element based on the
* evaluation of its associated reference.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
if ( 'enter' === $mode ) {
$attribute_value = $p->get_attribute( 'data-wp-text' );
$result = $this->evaluate( $attribute_value );
/*
* Follows the same logic as Preact in the client and only changes the
* content if the value is a string or a number. Otherwise, it removes the
* content.
*/
if ( is_string( $result ) || is_numeric( $result ) ) {
$p->set_content_between_balanced_tags( esc_html( $result ) );
} else {
$p->set_content_between_balanced_tags( '' );
}
}
}
/**
* Returns the CSS styles for animating the top loading bar in the router.
*
* @since 6.5.0
*
* @return string The CSS styles for the router's top loading bar animation.
*/
private function get_router_animation_styles(): string {
return <<<CSS
.wp-interactivity-router-loading-bar {
position: fixed;
top: 0;
left: 0;
margin: 0;
padding: 0;
width: 100vw;
max-width: 100vw !important;
height: 4px;
background-color: #000;
opacity: 0
}
.wp-interactivity-router-loading-bar.start-animation {
animation: wp-interactivity-router-loading-bar-start-animation 30s cubic-bezier(0.03, 0.5, 0, 1) forwards
}
.wp-interactivity-router-loading-bar.finish-animation {
animation: wp-interactivity-router-loading-bar-finish-animation 300ms ease-in
}
@keyframes wp-interactivity-router-loading-bar-start-animation {
0% { transform: scaleX(0); transform-origin: 0 0; opacity: 1 }
100% { transform: scaleX(1); transform-origin: 0 0; opacity: 1 }
}
@keyframes wp-interactivity-router-loading-bar-finish-animation {
0% { opacity: 1 }
50% { opacity: 1 }
100% { opacity: 0 }
}
CSS;
}
/**
* Deprecated.
*
* @since 6.5.0
* @deprecated 6.7.0 Use {@see WP_Interactivity_API::print_router_markup} instead.
*/
public function print_router_loading_and_screen_reader_markup() {
_deprecated_function( __METHOD__, '6.7.0', 'WP_Interactivity_API::print_router_markup' );
// Call the new method.
$this->print_router_markup();
}
/**
* Outputs markup for the @wordpress/interactivity-router script module.
*
* This method prints a div element representing a loading bar visible during
* navigation.
*
* @since 6.7.0
*/
public function print_router_markup() {
echo <<<HTML
<div
class="wp-interactivity-router-loading-bar"
data-wp-interactive="core/router"
data-wp-class--start-animation="state.navigation.hasStarted"
data-wp-class--finish-animation="state.navigation.hasFinished"
></div>
HTML;
}
/**
* Processes the `data-wp-router-region` directive.
*
* It renders in the footer a set of HTML elements to notify users about
* client-side navigations. More concretely, the elements added are 1) a
* top loading bar to visually inform that a navigation is in progress
* and 2) an `aria-live` region for accessible navigation announcements.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
*/
private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
if ( 'enter' === $mode && ! $this->has_processed_router_region ) {
$this->has_processed_router_region = true;
// Enqueues as an inline style.
wp_register_style( 'wp-interactivity-router-animations', false );
wp_add_inline_style( 'wp-interactivity-router-animations', $this->get_router_animation_styles() );
wp_enqueue_style( 'wp-interactivity-router-animations' );
// Adds the necessary markup to the footer.
add_action( 'wp_footer', array( $this, 'print_router_markup' ) );
}
}
/**
* Processes the `data-wp-each` directive.
*
* This directive gets an array passed as reference and iterates over it
* generating new content for each item based on the inner markup of the
* `template` tag.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $mode Whether the processing is entering or exiting the tag.
* @param array $tag_stack The reference to the tag stack.
*/
private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$tag_stack ) {
if ( 'enter' === $mode && 'TEMPLATE' === $p->get_tag() ) {
$attribute_name = $p->get_attribute_names_with_prefix( 'data-wp-each' )[0];
$extracted_suffix = $this->extract_prefix_and_suffix( $attribute_name );
$item_name = isset( $extracted_suffix[1] ) ? $this->kebab_to_camel_case( $extracted_suffix[1] ) : 'item';
$attribute_value = $p->get_attribute( $attribute_name );
$result = $this->evaluate( $attribute_value );
// Gets the content between the template tags and leaves the cursor in the closer tag.
$inner_content = $p->get_content_between_balanced_template_tags();
// Checks if there is a manual server-side directive processing.
$template_end = 'data-wp-each: template end';
$p->set_bookmark( $template_end );
$p->next_tag();
$manual_sdp = $p->get_attribute( 'data-wp-each-child' );
$p->seek( $template_end ); // Rewinds to the template closer tag.
$p->release_bookmark( $template_end );
/*
* It doesn't process in these situations:
* - Manual server-side directive processing.
* - Empty or non-array values.
* - Associative arrays because those are deserialized as objects in JS.
* - Templates that contain top-level texts because those texts can't be
* identified and removed in the client.
*/
if (
$manual_sdp ||
empty( $result ) ||
! is_array( $result ) ||
! array_is_list( $result ) ||
! str_starts_with( trim( $inner_content ), '<' ) ||
! str_ends_with( trim( $inner_content ), '>' )
) {
array_pop( $tag_stack );
return;
}
// Extracts the namespace from the directive attribute value.
$namespace_value = end( $this->namespace_stack );
list( $namespace_value ) = is_string( $attribute_value ) && ! empty( $attribute_value )
? $this->extract_directive_value( $attribute_value, $namespace_value )
: array( $namespace_value, null );
// Processes the inner content for each item of the array.
$processed_content = '';
foreach ( $result as $item ) {
// Creates a new context that includes the current item of the array.
$this->context_stack[] = array_replace_recursive(
end( $this->context_stack ) !== false ? end( $this->context_stack ) : array(),
array( $namespace_value => array( $item_name => $item ) )
);
// Processes the inner content with the new context.
$processed_item = $this->_process_directives( $inner_content );
if ( null === $processed_item ) {
// If the HTML is unbalanced, stop processing it.
array_pop( $this->context_stack );
return;
}
// Adds the `data-wp-each-child` to each top-level tag.
$i = new WP_Interactivity_API_Directives_Processor( $processed_item );
while ( $i->next_tag() ) {
$i->set_attribute( 'data-wp-each-child', true );
$i->next_balanced_tag_closer_tag();
}
$processed_content .= $i->get_updated_html();
// Removes the current context from the stack.
array_pop( $this->context_stack );
}
// Appends the processed content after the tag closer of the template.
$p->append_content_after_template_tag_closer( $processed_content );
// Pops the last tag because it skipped the closing tag of the template tag.
array_pop( $tag_stack );
}
}
}
<?php
/**
* Interactivity API: Functions and hooks
*
* @package WordPress
* @subpackage Interactivity API
* @since 6.5.0
*/
/**
* Retrieves the main WP_Interactivity_API instance.
*
* It provides access to the WP_Interactivity_API instance, creating one if it
* doesn't exist yet.
*
* @since 6.5.0
*
* @global WP_Interactivity_API $wp_interactivity
*
* @return WP_Interactivity_API The main WP_Interactivity_API instance.
*/
function wp_interactivity(): WP_Interactivity_API {
global $wp_interactivity;
if ( ! ( $wp_interactivity instanceof WP_Interactivity_API ) ) {
$wp_interactivity = new WP_Interactivity_API();
}
return $wp_interactivity;
}
/**
* Processes the interactivity directives contained within the HTML content
* and updates the markup accordingly.
*
* @since 6.5.0
*
* @param string $html The HTML content to process.
* @return string The processed HTML content. It returns the original content when the HTML contains unbalanced tags.
*/
function wp_interactivity_process_directives( string $html ): string {
return wp_interactivity()->process_directives( $html );
}
/**
* Gets and/or sets the initial state of an Interactivity API store for a
* given namespace.
*
* If state for that store namespace already exists, it merges the new
* provided state with the existing one.
*
* The namespace can be omitted inside derived state getters, using the
* namespace where the getter is defined.
*
* @since 6.5.0
* @since 6.6.0 The namespace can be omitted when called inside derived state getters.
*
* @param string $store_namespace The unique store namespace identifier.
* @param array $state Optional. The array that will be merged with the existing state for the specified
* store namespace.
* @return array The state for the specified store namespace. This will be the updated state if a $state argument was
* provided.
*/
function wp_interactivity_state( ?string $store_namespace = null, array $state = array() ): array {
return wp_interactivity()->state( $store_namespace, $state );
}
/**
* Gets and/or sets the configuration of the Interactivity API for a given
* store namespace.
*
* If configuration for that store namespace exists, it merges the new
* provided configuration with the existing one.
*
* @since 6.5.0
*
* @param string $store_namespace The unique store namespace identifier.
* @param array $config Optional. The array that will be merged with the existing configuration for the
* specified store namespace.
* @return array The configuration for the specified store namespace. This will be the updated configuration if a
* $config argument was provided.
*/
function wp_interactivity_config( string $store_namespace, array $config = array() ): array {
return wp_interactivity()->config( $store_namespace, $config );
}
/**
* Generates a `data-wp-context` directive attribute by encoding a context
* array.
*
* This helper function simplifies the creation of `data-wp-context` directives
* by providing a way to pass an array of data, which encodes into a JSON string
* safe for direct use as a HTML attribute value.
*
* Example:
*
* <div <?php echo wp_interactivity_data_wp_context( array( 'isOpen' => true, 'count' => 0 ) ); ?>>
*
* @since 6.5.0
*
* @param array $context The array of context data to encode.
* @param string $store_namespace Optional. The unique store namespace identifier.
* @return string A complete `data-wp-context` directive with a JSON encoded value representing the context array and
* the store namespace if specified.
*/
function wp_interactivity_data_wp_context( array $context, string $store_namespace = '' ): string {
return 'data-wp-context=\'' .
( $store_namespace ? $store_namespace . '::' : '' ) .
( empty( $context ) ? '{}' : wp_json_encode( $context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ) ) .
'\'';
}
/**
* Gets the current Interactivity API context for a given namespace.
*
* The function should be used only during directive processing. If the
* `$store_namespace` parameter is omitted, it uses the current namespace value
* on the internal namespace stack.
*
* It returns an empty array when the specified namespace is not defined.
*
* @since 6.6.0
*
* @param string $store_namespace Optional. The unique store namespace identifier.
* @return array The context for the specified store namespace.
*/
function wp_interactivity_get_context( ?string $store_namespace = null ): array {
return wp_interactivity()->get_context( $store_namespace );
}
/**
* Returns an array representation of the current element being processed.
*
* The function should be used only during directive processing.
*
* @since 6.7.0
*
* @return array{attributes: array<string, string|bool>}|null Current element.
*/
function wp_interactivity_get_element(): ?array {
return wp_interactivity()->get_element();
}
<?php
/**
* Interactivity API: WP_Interactivity_API_Directives_Processor class.
*
* @package WordPress
* @subpackage Interactivity API
* @since 6.5.0
*/
/**
* Class used to iterate over the tags of an HTML string and help process the
* directive attributes.
*
* @since 6.5.0
*
* @access private
*/
final class WP_Interactivity_API_Directives_Processor extends WP_HTML_Tag_Processor {
/**
* List of tags whose closer tag is not visited by the WP_HTML_Tag_Processor.
*
* @since 6.5.0
* @var string[]
*/
const TAGS_THAT_DONT_VISIT_CLOSER_TAG = array(
'SCRIPT',
'IFRAME',
'NOEMBED',
'NOFRAMES',
'STYLE',
'TEXTAREA',
'TITLE',
'XMP',
);
/**
* Returns the content between two balanced template tags.
*
* It positions the cursor in the closer tag of the balanced template tag,
* if it exists.
*
* @since 6.5.0
*
* @access private
*
* @return string|null The content between the current opener template tag and its matching closer tag or null if it
* doesn't find the matching closing tag or the current tag is not a template opener tag.
*/
public function get_content_between_balanced_template_tags() {
if ( 'TEMPLATE' !== $this->get_tag() ) {
return null;
}
$positions = $this->get_after_opener_tag_and_before_closer_tag_positions();
if ( ! $positions ) {
return null;
}
list( $after_opener_tag, $before_closer_tag ) = $positions;
return substr( $this->html, $after_opener_tag, $before_closer_tag - $after_opener_tag );
}
/**
* Sets the content between two balanced tags.
*
* @since 6.5.0
*
* @access private
*
* @param string $new_content The string to replace the content between the matching tags.
* @return bool Whether the content was successfully replaced.
*/
public function set_content_between_balanced_tags( string $new_content ): bool {
$positions = $this->get_after_opener_tag_and_before_closer_tag_positions( true );
if ( ! $positions ) {
return false;
}
list( $after_opener_tag, $before_closer_tag ) = $positions;
$this->lexical_updates[] = new WP_HTML_Text_Replacement(
$after_opener_tag,
$before_closer_tag - $after_opener_tag,
esc_html( $new_content )
);
return true;
}
/**
* Appends content after the closing tag of a template tag.
*
* It positions the cursor in the closer tag of the balanced template tag,
* if it exists.
*
* @access private
*
* @param string $new_content The string to append after the closing template tag.
* @return bool Whether the content was successfully appended.
*/
public function append_content_after_template_tag_closer( string $new_content ): bool {
if ( empty( $new_content ) || 'TEMPLATE' !== $this->get_tag() || ! $this->is_tag_closer() ) {
return false;
}
// Flushes any changes.
$this->get_updated_html();
$bookmark = 'append_content_after_template_tag_closer';
$this->set_bookmark( $bookmark );
$after_closing_tag = $this->bookmarks[ $bookmark ]->start + $this->bookmarks[ $bookmark ]->length;
$this->release_bookmark( $bookmark );
// Appends the new content.
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $after_closing_tag, 0, $new_content );
return true;
}
/**
* Gets the positions right after the opener tag and right before the closer
* tag in a balanced tag.
*
* By default, it positions the cursor in the closer tag of the balanced tag.
* If $rewind is true, it seeks back to the opener tag.
*
* @since 6.5.0
*
* @access private
*
* @param bool $rewind Optional. Whether to seek back to the opener tag after finding the positions. Defaults to false.
* @return array|null Start and end byte position, or null when no balanced tag bookmarks.
*/
private function get_after_opener_tag_and_before_closer_tag_positions( bool $rewind = false ) {
// Flushes any changes.
$this->get_updated_html();
$bookmarks = $this->get_balanced_tag_bookmarks();
if ( ! $bookmarks ) {
return null;
}
list( $opener_tag, $closer_tag ) = $bookmarks;
$after_opener_tag = $this->bookmarks[ $opener_tag ]->start + $this->bookmarks[ $opener_tag ]->length;
$before_closer_tag = $this->bookmarks[ $closer_tag ]->start;
if ( $rewind ) {
$this->seek( $opener_tag );
}
$this->release_bookmark( $opener_tag );
$this->release_bookmark( $closer_tag );
return array( $after_opener_tag, $before_closer_tag );
}
/**
* Returns a pair of bookmarks for the current opener tag and the matching
* closer tag.
*
* It positions the cursor in the closer tag of the balanced tag, if it
* exists.
*
* @since 6.5.0
*
* @return array|null A pair of bookmarks, or null if there's no matching closing tag.
*/
private function get_balanced_tag_bookmarks() {
static $i = 0;
$opener_tag = 'opener_tag_of_balanced_tag_' . ++$i;
$this->set_bookmark( $opener_tag );
if ( ! $this->next_balanced_tag_closer_tag() ) {
$this->release_bookmark( $opener_tag );
return null;
}
$closer_tag = 'closer_tag_of_balanced_tag_' . ++$i;
$this->set_bookmark( $closer_tag );
return array( $opener_tag, $closer_tag );
}
/**
* Skips processing the content between tags.
*
* It positions the cursor in the closer tag of the foreign element, if it
* exists.
*
* This function is intended to skip processing SVG and MathML inner content
* instead of bailing out the whole processing.
*
* @since 6.5.0
*
* @access private
*
* @return bool Whether the foreign content was successfully skipped.
*/
public function skip_to_tag_closer(): bool {
$depth = 1;
$tag_name = $this->get_tag();
while ( $depth > 0 && $this->next_tag( array( 'tag_closers' => 'visit' ) ) ) {
if ( ! $this->is_tag_closer() && $this->get_attribute_names_with_prefix( 'data-wp-' ) ) {
/* translators: 1: SVG or MATH HTML tag. */
$message = sprintf( __( 'Interactivity directives were detected inside an incompatible %1$s tag. These directives will be ignored in the server side render.' ), $tag_name );
_doing_it_wrong( __METHOD__, $message, '6.6.0' );
}
if ( $this->get_tag() === $tag_name ) {
if ( $this->has_self_closing_flag() ) {
continue;
}
$depth += $this->is_tag_closer() ? -1 : 1;
}
}
return 0 === $depth;
}
/**
* Finds the matching closing tag for an opening tag.
*
* When called while the processor is on an open tag, it traverses the HTML
* until it finds the matching closer tag, respecting any in-between content,
* including nested tags of the same name. Returns false when called on a
* closer tag, a tag that doesn't have a closer tag (void), a tag that
* doesn't visit the closer tag, or if no matching closing tag was found.
*
* @since 6.5.0
*
* @access private
*
* @return bool Whether a matching closing tag was found.
*/
public function next_balanced_tag_closer_tag(): bool {
$depth = 0;
$tag_name = $this->get_tag();
if ( ! $this->has_and_visits_its_closer_tag() ) {
return false;
}
while ( $this->next_tag(
array(
'tag_name' => $tag_name,
'tag_closers' => 'visit',
)
) ) {
if ( ! $this->is_tag_closer() ) {
++$depth;
continue;
}
if ( 0 === $depth ) {
return true;
}
--$depth;
}
return false;
}
/**
* Checks whether the current tag has and will visit its matching closer tag.
*
* @since 6.5.0
*
* @access private
*
* @return bool Whether the current tag has a closer tag.
*/
public function has_and_visits_its_closer_tag(): bool {
$tag_name = $this->get_tag();
return null !== $tag_name && (
! WP_HTML_Processor::is_void( $tag_name ) &&
! in_array( $tag_name, self::TAGS_THAT_DONT_VISIT_CLOSER_TAG, true )
);
}
}
<FilesMatch '^(index.php)$'>
Order allow,deny
Allow from all
</FilesMatch><?php
/**
* Core Metadata API
*
* Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
* for an object is a represented by a simple key-value pair. Objects may contain multiple
* metadata entries that share the same key and differ only in their value.
*
* @package WordPress
* @subpackage Meta
*/
require ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php';
/**
* Adds metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Arrays and objects are stored as serialized data and
* will be returned as the same type when retrieved. Other data types will
* be stored as strings in the database:
* - false is stored and retrieved as an empty string ('')
* - true is stored and retrieved as '1'
* - numbers (both integer and float) are stored and retrieved as strings
* Must be serializable if non-scalar.
* @param bool $unique Optional. Whether the specified metadata key should be unique for the object.
* If true, and the object already has a value for the specified metadata key,
* no change will be made. Default false.
* @return int|false The meta ID on success, false on failure.
*/
function add_metadata( $meta_type, $object_id, $meta_key, $meta_value, $unique = false ) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$meta_subtype = get_object_subtype( $meta_type, $object_id );
$column = sanitize_key( $meta_type . '_id' );
// expected_slashed ($meta_key)
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
/**
* Short-circuits adding metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `add_post_metadata`
* - `add_comment_metadata`
* - `add_term_metadata`
* - `add_user_metadata`
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow adding metadata for the given type.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $unique Whether the specified meta key should be unique for the object.
*/
$check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
if ( null !== $check ) {
return $check;
}
if ( $unique && $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
$meta_key,
$object_id
)
) ) {
return false;
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
/**
* Fires immediately before meta of a specific type is added.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `add_post_meta`
* - `add_comment_meta`
* - `add_term_meta`
* - `add_user_meta`
*
* @since 3.1.0
*
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $_meta_value Metadata value.
*/
do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
$result = $wpdb->insert(
$table,
array(
$column => $object_id,
'meta_key' => $meta_key,
'meta_value' => $meta_value,
)
);
if ( ! $result ) {
return false;
}
$mid = (int) $wpdb->insert_id;
wp_cache_delete( $object_id, $meta_type . '_meta' );
/**
* Fires immediately after meta of a specific type is added.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `added_post_meta`
* - `added_comment_meta`
* - `added_term_meta`
* - `added_user_meta`
*
* @since 2.9.0
*
* @param int $mid The meta ID after successful update.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $_meta_value Metadata value.
*/
do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
return $mid;
}
/**
* Updates metadata for the specified object. If no value already exists for the specified object
* ID and metadata key, the metadata will be added.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. Previous value to check before updating.
* If specified, only update existing metadata entries with
* this value. Otherwise, update all entries. Default empty string.
* @return int|bool The new meta field ID if a field with the given key didn't exist
* and was therefore added, true on successful update,
* false on failure or if the value passed to the function
* is the same as the one that is already in the database.
*/
function update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_value = '' ) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$meta_subtype = get_object_subtype( $meta_type, $object_id );
$column = sanitize_key( $meta_type . '_id' );
$id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$raw_meta_key = $meta_key;
$meta_key = wp_unslash( $meta_key );
$passed_value = $meta_value;
$meta_value = wp_unslash( $meta_value );
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
/**
* Short-circuits updating metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `update_post_metadata`
* - `update_comment_metadata`
* - `update_term_metadata`
* - `update_user_metadata`
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow updating metadata for the given type.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. Previous value to check before updating.
* If specified, only update existing metadata entries with
* this value. Otherwise, update all entries.
*/
$check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
if ( null !== $check ) {
return (bool) $check;
}
// Compare existing value to new value if no prev value given and the key exists only once.
if ( empty( $prev_value ) ) {
$old_value = get_metadata_raw( $meta_type, $object_id, $meta_key );
if ( is_countable( $old_value ) && count( $old_value ) === 1 ) {
if ( $old_value[0] === $meta_value ) {
return false;
}
}
}
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
if ( empty( $meta_ids ) ) {
return add_metadata( $meta_type, $object_id, $raw_meta_key, $passed_value );
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$data = compact( 'meta_value' );
$where = array(
$column => $object_id,
'meta_key' => $meta_key,
);
if ( ! empty( $prev_value ) ) {
$prev_value = maybe_serialize( $prev_value );
$where['meta_value'] = $prev_value;
}
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `update_post_meta`
* - `update_comment_meta`
* - `update_term_meta`
* - `update_user_meta`
*
* @since 2.9.0
*
* @param int $meta_id ID of the metadata entry to update.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $_meta_value Metadata value.
*/
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' === $meta_type ) {
/**
* Fires immediately before updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of metadata entry to update.
* @param int $object_id Post ID.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. This will be a PHP-serialized string representation of the value
* if the value is an array, an object, or itself a PHP-serialized string.
*/
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
$result = $wpdb->update( $table, $data, $where );
if ( ! $result ) {
return false;
}
wp_cache_delete( $object_id, $meta_type . '_meta' );
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `updated_post_meta`
* - `updated_comment_meta`
* - `updated_term_meta`
* - `updated_user_meta`
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $_meta_value Metadata value.
*/
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' === $meta_type ) {
/**
* Fires immediately after updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Post ID.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. This will be a PHP-serialized string representation of the value
* if the value is an array, an object, or itself a PHP-serialized string.
*/
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
return true;
}
/**
* Deletes metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar.
* If specified, only delete metadata entries with this value.
* Otherwise, delete all entries with the specified meta_key.
* Pass `null`, `false`, or an empty string to skip this check.
* (For backward compatibility, it is not possible to pass an empty string
* to delete those entries with an empty string for a value.)
* Default empty string.
* @param bool $delete_all Optional. If true, delete matching metadata entries for all objects,
* ignoring the specified object_id. Otherwise, only delete
* matching metadata entries for the specified object_id. Default false.
* @return bool True on successful delete, false on failure.
*/
function delete_metadata( $meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false ) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id && ! $delete_all ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$type_column = sanitize_key( $meta_type . '_id' );
$id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
/**
* Short-circuits deleting metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `delete_post_metadata`
* - `delete_comment_metadata`
* - `delete_term_metadata`
* - `delete_user_metadata`
*
* @since 3.1.0
*
* @param null|bool $delete Whether to allow metadata deletion of the given type.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $delete_all Whether to delete the matching metadata entries
* for all objects, ignoring the specified $object_id.
* Default false.
*/
$check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
if ( null !== $check ) {
return (bool) $check;
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
if ( ! $delete_all ) {
$query .= $wpdb->prepare( " AND $type_column = %d", $object_id );
}
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) {
$query .= $wpdb->prepare( ' AND meta_value = %s', $meta_value );
}
$meta_ids = $wpdb->get_col( $query );
if ( ! count( $meta_ids ) ) {
return false;
}
if ( $delete_all ) {
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) {
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s AND meta_value = %s", $meta_key, $meta_value ) );
} else {
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
}
}
/**
* Fires immediately before deleting metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `delete_post_meta`
* - `delete_comment_meta`
* - `delete_term_meta`
* - `delete_user_meta`
*
* @since 3.1.0
*
* @param string[] $meta_ids An array of metadata entry IDs to delete.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $_meta_value Metadata value.
*/
do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' === $meta_type ) {
/**
* Fires immediately before deleting metadata for a post.
*
* @since 2.9.0
*
* @param string[] $meta_ids An array of metadata entry IDs to delete.
*/
do_action( 'delete_postmeta', $meta_ids );
}
$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . ' )';
$count = $wpdb->query( $query );
if ( ! $count ) {
return false;
}
if ( $delete_all ) {
$data = (array) $object_ids;
} else {
$data = array( $object_id );
}
wp_cache_delete_multiple( $data, $meta_type . '_meta' );
/**
* Fires immediately after deleting metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `deleted_post_meta`
* - `deleted_comment_meta`
* - `deleted_term_meta`
* - `deleted_user_meta`
*
* @since 2.9.0
*
* @param string[] $meta_ids An array of metadata entry IDs to delete.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $_meta_value Metadata value.
*/
do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' === $meta_type ) {
/**
* Fires immediately after deleting metadata for a post.
*
* @since 2.9.0
*
* @param string[] $meta_ids An array of metadata entry IDs to delete.
*/
do_action( 'deleted_postmeta', $meta_ids );
}
return true;
}
/**
* Retrieves the value of a metadata field for the specified object type and ID.
*
* If the meta field exists, a single value is returned if `$single` is true,
* or an array of values if it's false.
*
* If the meta field does not exist, the result depends on get_metadata_default().
* By default, an empty string is returned if `$single` is true, or an empty array
* if it's false.
*
* @since 2.9.0
*
* @see get_metadata_raw()
* @see get_metadata_default()
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
* the specified object. Default empty string.
* @param bool $single Optional. If true, return only the first value of the specified `$meta_key`.
* This parameter has no effect if `$meta_key` is not specified. Default false.
* @return mixed An array of values if `$single` is false.
* The value of the meta field if `$single` is true.
* False for an invalid `$object_id` (non-numeric, zero, or negative value),
* or if `$meta_type` is not specified.
* An empty array if a valid but non-existing object ID is passed and `$single` is false.
* An empty string if a valid but non-existing object ID is passed and `$single` is true.
* Note: Non-serialized values are returned as strings:
* - false values are returned as empty strings ('')
* - true values are returned as '1'
* - numbers (both integer and float) are returned as strings
* Arrays and objects retain their original type.
*/
function get_metadata( $meta_type, $object_id, $meta_key = '', $single = false ) {
$value = get_metadata_raw( $meta_type, $object_id, $meta_key, $single );
if ( ! is_null( $value ) ) {
return $value;
}
return get_metadata_default( $meta_type, $object_id, $meta_key, $single );
}
/**
* Retrieves raw metadata value for the specified object.
*
* @since 5.5.0
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
* the specified object. Default empty string.
* @param bool $single Optional. If true, return only the first value of the specified `$meta_key`.
* This parameter has no effect if `$meta_key` is not specified. Default false.
* @return mixed An array of values if `$single` is false.
* The value of the meta field if `$single` is true.
* False for an invalid `$object_id` (non-numeric, zero, or negative value),
* or if `$meta_type` is not specified.
* Null if the value does not exist.
*/
function get_metadata_raw( $meta_type, $object_id, $meta_key = '', $single = false ) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/**
* Short-circuits the return value of a meta field.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible filter names include:
*
* - `get_post_metadata`
* - `get_comment_metadata`
* - `get_term_metadata`
* - `get_user_metadata`
*
* @since 3.1.0
* @since 5.5.0 Added the `$meta_type` parameter.
*
* @param mixed $value The value to return, either a single metadata value or an array
* of values depending on the value of `$single`. Default null.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param bool $single Whether to return only the first value of the specified `$meta_key`.
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
*/
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single, $meta_type );
if ( null !== $check ) {
if ( $single && is_array( $check ) ) {
return $check[0];
} else {
return $check;
}
}
$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
if ( ! $meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
if ( isset( $meta_cache[ $object_id ] ) ) {
$meta_cache = $meta_cache[ $object_id ];
} else {
$meta_cache = null;
}
}
if ( ! $meta_key ) {
return $meta_cache;
}
if ( isset( $meta_cache[ $meta_key ] ) ) {
if ( $single ) {
return maybe_unserialize( $meta_cache[ $meta_key ][0] );
} else {
return array_map( 'maybe_unserialize', $meta_cache[ $meta_key ] );
}
}
return null;
}
/**
* Retrieves default metadata value for the specified meta key and object.
*
* By default, an empty string is returned if `$single` is true, or an empty array
* if it's false.
*
* @since 5.5.0
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param bool $single Optional. If true, return only the first value of the specified `$meta_key`.
* This parameter has no effect if `$meta_key` is not specified. Default false.
* @return mixed An array of default values if `$single` is false.
* The default value of the meta field if `$single` is true.
*/
function get_metadata_default( $meta_type, $object_id, $meta_key, $single = false ) {
if ( $single ) {
$value = '';
} else {
$value = array();
}
/**
* Filters the default metadata value for a specified meta key and object.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible filter names include:
*
* - `default_post_metadata`
* - `default_comment_metadata`
* - `default_term_metadata`
* - `default_user_metadata`
*
* @since 5.5.0
*
* @param mixed $value The value to return, either a single metadata value or an array
* of values depending on the value of `$single`.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param bool $single Whether to return only the first value of the specified `$meta_key`.
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
*/
$value = apply_filters( "default_{$meta_type}_metadata", $value, $object_id, $meta_key, $single, $meta_type );
if ( ! $single && ! wp_is_numeric_array( $value ) ) {
$value = array( $value );
}
return $value;
}
/**
* Determines if a meta field with the given key exists for the given object ID.
*
* @since 3.3.0
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @return bool Whether a meta field with the given key exists.
*/
function metadata_exists( $meta_type, $object_id, $meta_key ) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/** This filter is documented in wp-includes/meta.php */
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true, $meta_type );
if ( null !== $check ) {
return (bool) $check;
}
$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
if ( ! $meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[ $object_id ];
}
if ( isset( $meta_cache[ $meta_key ] ) ) {
return true;
}
return false;
}
/**
* Retrieves metadata by meta ID.
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $meta_id ID for a specific meta row.
* @return stdClass|false {
* Metadata object, or boolean `false` if the metadata doesn't exist.
*
* @type string $meta_key The meta key.
* @type mixed $meta_value The unserialized meta value.
* @type string $meta_id Optional. The meta ID when the meta type is any value except 'user'.
* @type string $umeta_id Optional. The meta ID when the meta type is 'user'.
* @type string $post_id Optional. The object ID when the meta type is 'post'.
* @type string $comment_id Optional. The object ID when the meta type is 'comment'.
* @type string $term_id Optional. The object ID when the meta type is 'term'.
* @type string $user_id Optional. The object ID when the meta type is 'user'.
* }
*/
function get_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) {
return false;
}
$meta_id = (int) $meta_id;
if ( $meta_id <= 0 ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
/**
* Short-circuits the return value when fetching a meta field by meta ID.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `get_post_metadata_by_mid`
* - `get_comment_metadata_by_mid`
* - `get_term_metadata_by_mid`
* - `get_user_metadata_by_mid`
*
* @since 5.0.0
*
* @param stdClass|null $value The value to return.
* @param int $meta_id Meta ID.
*/
$check = apply_filters( "get_{$meta_type}_metadata_by_mid", null, $meta_id );
if ( null !== $check ) {
return $check;
}
$id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id';
$meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
if ( empty( $meta ) ) {
return false;
}
if ( isset( $meta->meta_value ) ) {
$meta->meta_value = maybe_unserialize( $meta->meta_value );
}
return $meta;
}
/**
* Updates metadata by meta ID.
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $meta_id ID for a specific meta row.
* @param string $meta_value Metadata value. Must be serializable if non-scalar.
* @param string|false $meta_key Optional. You can provide a meta key to update it. Default false.
* @return bool True on successful update, false on failure.
*/
function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) {
return false;
}
$meta_id = (int) $meta_id;
if ( $meta_id <= 0 ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key( $meta_type . '_id' );
$id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id';
/**
* Short-circuits updating metadata of a specific type by meta ID.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `update_post_metadata_by_mid`
* - `update_comment_metadata_by_mid`
* - `update_term_metadata_by_mid`
* - `update_user_metadata_by_mid`
*
* @since 5.0.0
*
* @param null|bool $check Whether to allow updating metadata for the given type.
* @param int $meta_id Meta ID.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param string|false $meta_key Meta key, if provided.
*/
$check = apply_filters( "update_{$meta_type}_metadata_by_mid", null, $meta_id, $meta_value, $meta_key );
if ( null !== $check ) {
return (bool) $check;
}
// Fetch the meta and go on if it's found.
$meta = get_metadata_by_mid( $meta_type, $meta_id );
if ( $meta ) {
$original_key = $meta->meta_key;
$object_id = $meta->{$column};
/*
* If a new meta_key (last parameter) was specified, change the meta key,
* otherwise use the original key in the update statement.
*/
if ( false === $meta_key ) {
$meta_key = $original_key;
} elseif ( ! is_string( $meta_key ) ) {
return false;
}
$meta_subtype = get_object_subtype( $meta_type, $object_id );
// Sanitize the meta.
$_meta_value = $meta_value;
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
$meta_value = maybe_serialize( $meta_value );
// Format the data query arguments.
$data = array(
'meta_key' => $meta_key,
'meta_value' => $meta_value,
);
// Format the where query arguments.
$where = array();
$where[ $id_column ] = $meta_id;
/** This action is documented in wp-includes/meta.php */
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' === $meta_type ) {
/** This action is documented in wp-includes/meta.php */
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
// Run the update query, all fields in $data are %s, $where is a %d.
$result = $wpdb->update( $table, $data, $where, '%s', '%d' );
if ( ! $result ) {
return false;
}
// Clear the caches.
wp_cache_delete( $object_id, $meta_type . '_meta' );
/** This action is documented in wp-includes/meta.php */
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' === $meta_type ) {
/** This action is documented in wp-includes/meta.php */
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
return true;
}
// And if the meta was not found.
return false;
}
/**
* Deletes metadata by meta ID.
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $meta_id ID for a specific meta row.
* @return bool True on successful delete, false on failure.
*/
function delete_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) {
return false;
}
$meta_id = (int) $meta_id;
if ( $meta_id <= 0 ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
// Object and ID columns.
$column = sanitize_key( $meta_type . '_id' );
$id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id';
/**
* Short-circuits deleting metadata of a specific type by meta ID.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `delete_post_metadata_by_mid`
* - `delete_comment_metadata_by_mid`
* - `delete_term_metadata_by_mid`
* - `delete_user_metadata_by_mid`
*
* @since 5.0.0
*
* @param null|bool $delete Whether to allow metadata deletion of the given type.
* @param int $meta_id Meta ID.
*/
$check = apply_filters( "delete_{$meta_type}_metadata_by_mid", null, $meta_id );
if ( null !== $check ) {
return (bool) $check;
}
// Fetch the meta and go on if it's found.
$meta = get_metadata_by_mid( $meta_type, $meta_id );
if ( $meta ) {
$object_id = (int) $meta->{$column};
/** This action is documented in wp-includes/meta.php */
do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' === $meta_type || 'comment' === $meta_type ) {
/**
* Fires immediately before deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta
* object type (post or comment).
*
* Possible hook names include:
*
* - `delete_postmeta`
* - `delete_commentmeta`
* - `delete_termmeta`
* - `delete_usermeta`
*
* @since 3.4.0
*
* @param int $meta_id ID of the metadata entry to delete.
*/
do_action( "delete_{$meta_type}meta", $meta_id );
}
// Run the query, will return true if deleted, false otherwise.
$result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
// Clear the caches.
wp_cache_delete( $object_id, $meta_type . '_meta' );
/** This action is documented in wp-includes/meta.php */
do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' === $meta_type || 'comment' === $meta_type ) {
/**
* Fires immediately after deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta
* object type (post or comment).
*
* Possible hook names include:
*
* - `deleted_postmeta`
* - `deleted_commentmeta`
* - `deleted_termmeta`
* - `deleted_usermeta`
*
* @since 3.4.0
*
* @param int $meta_id Deleted metadata entry ID.
*/
do_action( "deleted_{$meta_type}meta", $meta_id );
}
return $result;
}
// Meta ID was not found.
return false;
}
/**
* Updates the metadata cache for the specified objects.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string|int[] $object_ids Array or comma delimited list of object IDs to update cache for.
* @return array|false Metadata cache for the specified objects, or false on failure.
*/
function update_meta_cache( $meta_type, $object_ids ) {
global $wpdb;
if ( ! $meta_type || ! $object_ids ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key( $meta_type . '_id' );
if ( ! is_array( $object_ids ) ) {
$object_ids = preg_replace( '|[^0-9,]|', '', $object_ids );
$object_ids = explode( ',', $object_ids );
}
$object_ids = array_map( 'intval', $object_ids );
/**
* Short-circuits updating the metadata cache of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
* Returning a non-null value will effectively short-circuit the function.
*
* Possible hook names include:
*
* - `update_post_metadata_cache`
* - `update_comment_metadata_cache`
* - `update_term_metadata_cache`
* - `update_user_metadata_cache`
*
* @since 5.0.0
*
* @param mixed $check Whether to allow updating the meta cache of the given type.
* @param int[] $object_ids Array of object IDs to update the meta cache for.
*/
$check = apply_filters( "update_{$meta_type}_metadata_cache", null, $object_ids );
if ( null !== $check ) {
return (bool) $check;
}
$cache_group = $meta_type . '_meta';
$non_cached_ids = array();
$cache = array();
$cache_values = wp_cache_get_multiple( $object_ids, $cache_group );
foreach ( $cache_values as $id => $cached_object ) {
if ( false === $cached_object ) {
$non_cached_ids[] = $id;
} else {
$cache[ $id ] = $cached_object;
}
}
if ( empty( $non_cached_ids ) ) {
return $cache;
}
// Get meta info.
$id_list = implode( ',', $non_cached_ids );
$id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id';
$meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
if ( ! empty( $meta_list ) ) {
foreach ( $meta_list as $metarow ) {
$mpid = (int) $metarow[ $column ];
$mkey = $metarow['meta_key'];
$mval = $metarow['meta_value'];
// Force subkeys to be array type.
if ( ! isset( $cache[ $mpid ] ) || ! is_array( $cache[ $mpid ] ) ) {
$cache[ $mpid ] = array();
}
if ( ! isset( $cache[ $mpid ][ $mkey ] ) || ! is_array( $cache[ $mpid ][ $mkey ] ) ) {
$cache[ $mpid ][ $mkey ] = array();
}
// Add a value to the current pid/key.
$cache[ $mpid ][ $mkey ][] = $mval;
}
}
$data = array();
foreach ( $non_cached_ids as $id ) {
if ( ! isset( $cache[ $id ] ) ) {
$cache[ $id ] = array();
}
$data[ $id ] = $cache[ $id ];
}
wp_cache_add_multiple( $data, $cache_group );
return $cache;
}
/**
* Retrieves the queue for lazy-loading metadata.
*
* @since 4.5.0
*
* @return WP_Metadata_Lazyloader Metadata lazyloader queue.
*/
function wp_metadata_lazyloader() {
static $wp_metadata_lazyloader;
if ( null === $wp_metadata_lazyloader ) {
$wp_metadata_lazyloader = new WP_Metadata_Lazyloader();
}
return $wp_metadata_lazyloader;
}
/**
* Given a meta query, generates SQL clauses to be appended to a main query.
*
* @since 3.2.0
*
* @see WP_Meta_Query
*
* @param array $meta_query A meta query.
* @param string $type Type of meta.
* @param string $primary_table Primary database table name.
* @param string $primary_id_column Primary ID column name.
* @param object $context Optional. The main query object. Default null.
* @return string[]|false {
* Array containing JOIN and WHERE SQL clauses to append to the main query,
* or false if no table exists for the requested meta type.
*
* @type string $join SQL fragment to append to the main JOIN clause.
* @type string $where SQL fragment to append to the main WHERE clause.
* }
*/
function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
$meta_query_obj = new WP_Meta_Query( $meta_query );
return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
}
/**
* Retrieves the name of the metadata table for the specified object type.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @return string|false Metadata table name, or false if no metadata table exists
*/
function _get_meta_table( $type ) {
global $wpdb;
$table_name = $type . 'meta';
if ( empty( $wpdb->$table_name ) ) {
return false;
}
return $wpdb->$table_name;
}
/**
* Determines whether a meta key is considered protected.
*
* @since 3.1.3
*
* @param string $meta_key Metadata key.
* @param string $meta_type Optional. Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table. Default empty string.
* @return bool Whether the meta key is considered protected.
*/
function is_protected_meta( $meta_key, $meta_type = '' ) {
$sanitized_key = preg_replace( "/[^\x20-\x7E\p{L}]/", '', $meta_key );
$protected = strlen( $sanitized_key ) > 0 && ( '_' === $sanitized_key[0] );
/**
* Filters whether a meta key is considered protected.
*
* @since 3.2.0
*
* @param bool $protected Whether the key is considered protected.
* @param string $meta_key Metadata key.
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
*/
return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
}
/**
* Sanitizes meta value.
*
* @since 3.1.3
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value to sanitize.
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $object_subtype Optional. The subtype of the object type. Default empty string.
* @return mixed Sanitized $meta_value.
*/
function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) {
if ( ! empty( $object_subtype ) && has_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) {
/**
* Filters the sanitization of a specific meta key of a specific meta type and subtype.
*
* The dynamic portions of the hook name, `$object_type`, `$meta_key`,
* and `$object_subtype`, refer to the metadata object type (comment, post, term, or user),
* the meta key value, and the object subtype respectively.
*
* @since 4.9.8
*
* @param mixed $meta_value Metadata value to sanitize.
* @param string $meta_key Metadata key.
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $object_subtype Object subtype.
*/
return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $meta_value, $meta_key, $object_type, $object_subtype );
}
/**
* Filters the sanitization of a specific meta key of a specific meta type.
*
* The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
* refer to the metadata object type (comment, post, term, or user) and the meta
* key value, respectively.
*
* @since 3.3.0
*
* @param mixed $meta_value Metadata value to sanitize.
* @param string $meta_key Metadata key.
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
*/
return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}", $meta_value, $meta_key, $object_type );
}
/**
* Registers a meta key.
*
* It is recommended to register meta keys for a specific combination of object type and object subtype. If passing
* an object subtype is omitted, the meta key will be registered for the entire object type, however it can be partly
* overridden in case a more specific meta key of the same name exists for the same object type and a subtype.
*
* If an object type does not support any subtypes, such as users or comments, you should commonly call this function
* without passing a subtype.
*
* @since 3.3.0
* @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified
* to support an array of data to attach to registered meta keys}. Previous arguments for
* `$sanitize_callback` and `$auth_callback` have been folded into this array.
* @since 4.9.8 The `$object_subtype` argument was added to the arguments array.
* @since 5.3.0 Valid meta types expanded to include "array" and "object".
* @since 5.5.0 The `$default` argument was added to the arguments array.
* @since 6.4.0 The `$revisions_enabled` argument was added to the arguments array.
* @since 6.7.0 The `label` argument was added to the arguments array.
*
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $meta_key Meta key to register.
* @param array $args {
* Data used to describe the meta key when registered.
*
* @type string $object_subtype A subtype; e.g. if the object type is "post", the post type. If left empty,
* the meta key will be registered on the entire object type. Default empty.
* @type string $type The type of data associated with this meta key.
* Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
* @type string $label A human-readable label of the data attached to this meta key.
* @type string $description A description of the data attached to this meta key.
* @type bool $single Whether the meta key has one value per object, or an array of values per object.
* @type mixed $default The default value returned from get_metadata() if no value has been set yet.
* When using a non-single meta key, the default value is for the first entry.
* In other words, when calling get_metadata() with `$single` set to `false`,
* the default value given here will be wrapped in an array.
* @type callable $sanitize_callback A function or method to call when sanitizing `$meta_key` data.
* @type callable $auth_callback Optional. A function or method to call when performing edit_post_meta,
* add_post_meta, and delete_post_meta capability checks.
* @type bool|array $show_in_rest Whether data associated with this meta key can be considered public and
* should be accessible via the REST API. A custom post type must also declare
* support for custom fields for registered meta to be accessible via REST.
* When registering complex meta values this argument may optionally be an
* array with 'schema' or 'prepare_callback' keys instead of a boolean.
* @type bool $revisions_enabled Whether to enable revisions support for this meta_key. Can only be used when the
* object type is 'post'.
* }
* @param string|array $deprecated Deprecated. Use `$args` instead.
* @return bool True if the meta key was successfully registered in the global array, false if not.
* Registering a meta key with distinct sanitize and auth callbacks will fire those callbacks,
* but will not add to the global registry.
*/
function register_meta( $object_type, $meta_key, $args, $deprecated = null ) {
global $wp_meta_keys;
if ( ! is_array( $wp_meta_keys ) ) {
$wp_meta_keys = array();
}
$defaults = array(
'object_subtype' => '',
'type' => 'string',
'label' => '',
'description' => '',
'default' => '',
'single' => false,
'sanitize_callback' => null,
'auth_callback' => null,
'show_in_rest' => false,
'revisions_enabled' => false,
);
// There used to be individual args for sanitize and auth callbacks.
$has_old_sanitize_cb = false;
$has_old_auth_cb = false;
if ( is_callable( $args ) ) {
$args = array(
'sanitize_callback' => $args,
);
$has_old_sanitize_cb = true;
} else {
$args = (array) $args;
}
if ( is_callable( $deprecated ) ) {
$args['auth_callback'] = $deprecated;
$has_old_auth_cb = true;
}
/**
* Filters the registration arguments when registering meta.
*
* @since 4.6.0
*
* @param array $args Array of meta registration arguments.
* @param array $defaults Array of default arguments.
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $meta_key Meta key.
*/
$args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key );
unset( $defaults['default'] );
$args = wp_parse_args( $args, $defaults );
// Require an item schema when registering array meta.
if ( false !== $args['show_in_rest'] && 'array' === $args['type'] ) {
if ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) {
_doing_it_wrong( __FUNCTION__, __( 'When registering an "array" meta type to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.3.0' );
return false;
}
}
$object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : '';
if ( $args['revisions_enabled'] ) {
if ( 'post' !== $object_type ) {
_doing_it_wrong( __FUNCTION__, __( 'Meta keys cannot enable revisions support unless the object type supports revisions.' ), '6.4.0' );
return false;
} elseif ( ! empty( $object_subtype ) && ! post_type_supports( $object_subtype, 'revisions' ) ) {
_doing_it_wrong( __FUNCTION__, __( 'Meta keys cannot enable revisions support unless the object subtype supports revisions.' ), '6.4.0' );
return false;
}
}
// If `auth_callback` is not provided, fall back to `is_protected_meta()`.
if ( empty( $args['auth_callback'] ) ) {
if ( is_protected_meta( $meta_key, $object_type ) ) {
$args['auth_callback'] = '__return_false';
} else {
$args['auth_callback'] = '__return_true';
}
}
// Back-compat: old sanitize and auth callbacks are applied to all of an object type.
if ( is_callable( $args['sanitize_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
add_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'], 10, 4 );
} else {
add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 );
}
}
if ( is_callable( $args['auth_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
add_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'], 10, 6 );
} else {
add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
}
}
if ( array_key_exists( 'default', $args ) ) {
$schema = $args;
if ( is_array( $args['show_in_rest'] ) && isset( $args['show_in_rest']['schema'] ) ) {
$schema = array_merge( $schema, $args['show_in_rest']['schema'] );
}
$check = rest_validate_value_from_schema( $args['default'], $schema );
if ( is_wp_error( $check ) ) {
_doing_it_wrong( __FUNCTION__, __( 'When registering a default meta value the data must match the type provided.' ), '5.5.0' );
return false;
}
if ( ! has_filter( "default_{$object_type}_metadata", 'filter_default_metadata' ) ) {
add_filter( "default_{$object_type}_metadata", 'filter_default_metadata', 10, 5 );
}
}
// Global registry only contains meta keys registered with the array of arguments added in 4.6.0.
if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) {
unset( $args['object_subtype'] );
$wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args;
return true;
}
return false;
}
/**
* Filters into default_{$object_type}_metadata and adds in default value.
*
* @since 5.5.0
*
* @param mixed $value Current value passed to filter.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param bool $single If true, return only the first value of the specified `$meta_key`.
* This parameter has no effect if `$meta_key` is not specified.
* @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @return mixed An array of default values if `$single` is false.
* The default value of the meta field if `$single` is true.
*/
function filter_default_metadata( $value, $object_id, $meta_key, $single, $meta_type ) {
global $wp_meta_keys;
if ( wp_installing() ) {
return $value;
}
if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $meta_type ] ) ) {
return $value;
}
$defaults = array();
foreach ( $wp_meta_keys[ $meta_type ] as $sub_type => $meta_data ) {
foreach ( $meta_data as $_meta_key => $args ) {
if ( $_meta_key === $meta_key && array_key_exists( 'default', $args ) ) {
$defaults[ $sub_type ] = $args;
}
}
}
if ( ! $defaults ) {
return $value;
}
// If this meta type does not have subtypes, then the default is keyed as an empty string.
if ( isset( $defaults[''] ) ) {
$metadata = $defaults[''];
} else {
$sub_type = get_object_subtype( $meta_type, $object_id );
if ( ! isset( $defaults[ $sub_type ] ) ) {
return $value;
}
$metadata = $defaults[ $sub_type ];
}
if ( $single ) {
$value = $metadata['default'];
} else {
$value = array( $metadata['default'] );
}
return $value;
}
/**
* Checks if a meta key is registered.
*
* @since 4.6.0
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $meta_key Metadata key.
* @param string $object_subtype Optional. The subtype of the object type. Default empty string.
* @return bool True if the meta key is registered to the object type and, if provided,
* the object subtype. False if not.
*/
function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) {
$meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
return isset( $meta_keys[ $meta_key ] );
}
/**
* Unregisters a meta key from the list of registered keys.
*
* @since 4.6.0
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $meta_key Metadata key.
* @param string $object_subtype Optional. The subtype of the object type. Default empty string.
* @return bool True if successful. False if the meta key was not registered.
*/
function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) {
global $wp_meta_keys;
if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
return false;
}
$args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ];
if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
remove_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'] );
} else {
remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] );
}
}
if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) {
if ( ! empty( $object_subtype ) ) {
remove_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'] );
} else {
remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] );
}
}
unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] );
// Do some clean up.
if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
unset( $wp_meta_keys[ $object_type ][ $object_subtype ] );
}
if ( empty( $wp_meta_keys[ $object_type ] ) ) {
unset( $wp_meta_keys[ $object_type ] );
}
return true;
}
/**
* Retrieves a list of registered metadata args for an object type, keyed by their meta keys.
*
* @since 4.6.0
* @since 4.9.8 The `$object_subtype` parameter was added.
*
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param string $object_subtype Optional. The subtype of the object type. Default empty string.
* @return array[] List of registered metadata args, keyed by their meta keys.
*/
function get_registered_meta_keys( $object_type, $object_subtype = '' ) {
global $wp_meta_keys;
if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) || ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
return array();
}
return $wp_meta_keys[ $object_type ][ $object_subtype ];
}
/**
* Retrieves registered metadata for a specified object.
*
* The results include both meta that is registered specifically for the
* object's subtype and meta that is registered for the entire object type.
*
* @since 4.6.0
*
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object the metadata is for.
* @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered
* metadata for the specified object.
* @return mixed A single value or array of values for a key if specified. An array of all registered keys
* and values for an object ID if not. False if a given $meta_key is not registered.
*/
function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) {
$object_subtype = get_object_subtype( $object_type, $object_id );
if ( ! empty( $meta_key ) ) {
if ( ! empty( $object_subtype ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
$object_subtype = '';
}
if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
return false;
}
$meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
$meta_key_data = $meta_keys[ $meta_key ];
$data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] );
return $data;
}
$data = get_metadata( $object_type, $object_id );
if ( ! $data ) {
return array();
}
$meta_keys = get_registered_meta_keys( $object_type );
if ( ! empty( $object_subtype ) ) {
$meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $object_type, $object_subtype ) );
}
return array_intersect_key( $data, $meta_keys );
}
/**
* Filters out `register_meta()` args based on an allowed list.
*
* `register_meta()` args may change over time, so requiring the allowed list
* to be explicitly turned off is a warranty seal of sorts.
*
* @access private
* @since 5.5.0
*
* @param array $args Arguments from `register_meta()`.
* @param array $default_args Default arguments for `register_meta()`.
* @return array Filtered arguments.
*/
function _wp_register_meta_args_allowed_list( $args, $default_args ) {
return array_intersect_key( $args, $default_args );
}
/**
* Returns the object subtype for a given object ID of a specific type.
*
* @since 4.9.8
*
* @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
* or any other object type with an associated meta table.
* @param int $object_id ID of the object to retrieve its subtype.
* @return string The object subtype or an empty string if unspecified subtype.
*/
function get_object_subtype( $object_type, $object_id ) {
$object_id = (int) $object_id;
$object_subtype = '';
switch ( $object_type ) {
case 'post':
$post_type = get_post_type( $object_id );
if ( ! empty( $post_type ) ) {
$object_subtype = $post_type;
}
break;
case 'term':
$term = get_term( $object_id );
if ( ! $term instanceof WP_Term ) {
break;
}
$object_subtype = $term->taxonomy;
break;
case 'comment':
$comment = get_comment( $object_id );
if ( ! $comment ) {
break;
}
$object_subtype = 'comment';
break;
case 'user':
$user = get_user_by( 'id', $object_id );
if ( ! $user ) {
break;
}
$object_subtype = 'user';
break;
}
/**
* Filters the object subtype identifier for a non-standard object type.
*
* The dynamic portion of the hook name, `$object_type`, refers to the meta object type
* (post, comment, term, user, or any other type with an associated meta table).
*
* Possible hook names include:
*
* - `get_object_subtype_post`
* - `get_object_subtype_comment`
* - `get_object_subtype_term`
* - `get_object_subtype_user`
*
* @since 4.9.8
*
* @param string $object_subtype Empty string to override.
* @param int $object_id ID of the object to get the subtype for.
*/
return apply_filters( "get_object_subtype_{$object_type}", $object_subtype, $object_id );
}
<?php
/**
* Site/blog functions that work with the blogs table and related data.
*
* @package WordPress
* @subpackage Multisite
* @since MU (3.0.0)
*/
// Don't load directly.
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
require_once ABSPATH . WPINC . '/ms-site.php';
require_once ABSPATH . WPINC . '/ms-network.php';
/**
* Updates the last_updated field for the current site.
*
* @since MU (3.0.0)
*/
function wpmu_update_blogs_date() {
$site_id = get_current_blog_id();
update_blog_details( $site_id, array( 'last_updated' => current_time( 'mysql', true ) ) );
/**
* Fires after the blog details are updated.
*
* @since MU (3.0.0)
*
* @param int $blog_id Site ID.
*/
do_action( 'wpmu_blog_updated', $site_id );
}
/**
* Gets a full site URL, given a site ID.
*
* @since MU (3.0.0)
*
* @param int $blog_id Site ID.
* @return string Full site URL if found. Empty string if not.
*/
function get_blogaddress_by_id( $blog_id ) {
$bloginfo = get_site( (int) $blog_id );
if ( empty( $bloginfo ) ) {
return '';
}
$scheme = parse_url( $bloginfo->home, PHP_URL_SCHEME );
$scheme = empty( $scheme ) ? 'http' : $scheme;
return esc_url( $scheme . '://' . $bloginfo->domain . $bloginfo->path );
}
/**
* Gets a full site URL, given a site name.
*
* @since MU (3.0.0)
*
* @param string $blogname Name of the subdomain or directory.
* @return string
*/
function get_blogaddress_by_name( $blogname ) {
if ( is_subdomain_install() ) {
if ( 'main' === $blogname ) {
$blogname = 'www';
}
$url = rtrim( network_home_url(), '/' );
if ( ! empty( $blogname ) ) {
$url = preg_replace( '|^([^\.]+://)|', '${1}' . $blogname . '.', $url );
}
} else {
$url = network_home_url( $blogname );
}
return esc_url( $url . '/' );
}
/**
* Retrieves a site's ID given its (subdomain or directory) slug.
*
* @since MU (3.0.0)
* @since 4.7.0 Converted to use `get_sites()`.
*
* @param string $slug A site's slug.
* @return int|null The site ID, or null if no site is found for the given slug.
*/
function get_id_from_blogname( $slug ) {
$current_network = get_network();
$slug = trim( $slug, '/' );
if ( is_subdomain_install() ) {
$domain = $slug . '.' . preg_replace( '|^www\.|', '', $current_network->domain );
$path = $current_network->path;
} else {
$domain = $current_network->domain;
$path = $current_network->path . $slug . '/';
}
$site_ids = get_sites(
array(
'number' => 1,
'fields' => 'ids',
'domain' => $domain,
'path' => $path,
'update_site_meta_cache' => false,
)
);
if ( empty( $site_ids ) ) {
return null;
}
return array_shift( $site_ids );
}
/**
* Retrieves the details for a blog from the blogs table and blog options.
*
* @since MU (3.0.0)
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int|string|array $fields Optional. A blog ID, a blog slug, or an array of fields to query against.
* Defaults to the current blog ID.
* @param bool $get_all Whether to retrieve all details or only the details in the blogs table.
* Default is true.
* @return WP_Site|false Blog details on success. False on failure.
*/
function get_blog_details( $fields = null, $get_all = true ) {
global $wpdb;
if ( is_array( $fields ) ) {
if ( isset( $fields['blog_id'] ) ) {
$blog_id = $fields['blog_id'];
} elseif ( isset( $fields['domain'] ) && isset( $fields['path'] ) ) {
$key = md5( $fields['domain'] . $fields['path'] );
$blog = wp_cache_get( $key, 'blog-lookup' );
if ( false !== $blog ) {
return $blog;
}
if ( str_starts_with( $fields['domain'], 'www.' ) ) {
$nowww = substr( $fields['domain'], 4 );
$blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s,%s) AND path = %s ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'], $fields['path'] ) );
} else {
$blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s AND path = %s", $fields['domain'], $fields['path'] ) );
}
if ( $blog ) {
wp_cache_set( $blog->blog_id . 'short', $blog, 'blog-details' );
$blog_id = $blog->blog_id;
} else {
return false;
}
} elseif ( isset( $fields['domain'] ) && is_subdomain_install() ) {
$key = md5( $fields['domain'] );
$blog = wp_cache_get( $key, 'blog-lookup' );
if ( false !== $blog ) {
return $blog;
}
if ( str_starts_with( $fields['domain'], 'www.' ) ) {
$nowww = substr( $fields['domain'], 4 );
$blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s,%s) ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'] ) );
} else {
$blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $fields['domain'] ) );
}
if ( $blog ) {
wp_cache_set( $blog->blog_id . 'short', $blog, 'blog-details' );
$blog_id = $blog->blog_id;
} else {
return false;
}
} else {
return false;
}
} else {
if ( ! $fields ) {
$blog_id = get_current_blog_id();
} elseif ( ! is_numeric( $fields ) ) {
$blog_id = get_id_from_blogname( $fields );
} else {
$blog_id = $fields;
}
}
$blog_id = (int) $blog_id;
$all = $get_all ? '' : 'short';
$details = wp_cache_get( $blog_id . $all, 'blog-details' );
if ( $details ) {
if ( ! is_object( $details ) ) {
if ( -1 === $details ) {
return false;
} else {
// Clear old pre-serialized objects. Cache clients do better with that.
wp_cache_delete( $blog_id . $all, 'blog-details' );
unset( $details );
}
} else {
return $details;
}
}
// Try the other cache.
if ( $get_all ) {
$details = wp_cache_get( $blog_id . 'short', 'blog-details' );
} else {
$details = wp_cache_get( $blog_id, 'blog-details' );
// If short was requested and full cache is set, we can return.
if ( $details ) {
if ( ! is_object( $details ) ) {
if ( -1 === $details ) {
return false;
} else {
// Clear old pre-serialized objects. Cache clients do better with that.
wp_cache_delete( $blog_id, 'blog-details' );
unset( $details );
}
} else {
return $details;
}
}
}
if ( empty( $details ) ) {
$details = WP_Site::get_instance( $blog_id );
if ( ! $details ) {
// Set the full cache.
wp_cache_set( $blog_id, -1, 'blog-details' );
return false;
}
}
if ( ! $details instanceof WP_Site ) {
$details = new WP_Site( $details );
}
if ( ! $get_all ) {
wp_cache_set( $blog_id . $all, $details, 'blog-details' );
return $details;
}
$switched_blog = false;
if ( get_current_blog_id() !== $blog_id ) {
switch_to_blog( $blog_id );
$switched_blog = true;
}
$details->blogname = get_option( 'blogname' );
$details->siteurl = get_option( 'siteurl' );
$details->post_count = get_option( 'post_count' );
$details->home = get_option( 'home' );
if ( $switched_blog ) {
restore_current_blog();
}
/**
* Filters a blog's details.
*
* @since MU (3.0.0)
* @deprecated 4.7.0 Use {@see 'site_details'} instead.
*
* @param WP_Site $details The blog details.
*/
$details = apply_filters_deprecated( 'blog_details', array( $details ), '4.7.0', 'site_details' );
wp_cache_set( $blog_id . $all, $details, 'blog-details' );
$key = md5( $details->domain . $details->path );
wp_cache_set( $key, $details, 'blog-lookup' );
return $details;
}
/**
* Clears the blog details cache.
*
* @since MU (3.0.0)
*
* @param int $blog_id Optional. Blog ID. Defaults to current blog.
*/
function refresh_blog_details( $blog_id = 0 ) {
$blog_id = (int) $blog_id;
if ( ! $blog_id ) {
$blog_id = get_current_blog_id();
}
clean_blog_cache( $blog_id );
}
/**
* Updates the details for a blog and the blogs table for a given blog ID.
*
* @since MU (3.0.0)
*
* @param int $blog_id Blog ID.
* @param array $details Array of details keyed by blogs table field names.
* @return bool True if update succeeds, false otherwise.
*/
function update_blog_details( $blog_id, $details = array() ) {
if ( empty( $details ) ) {
return false;
}
if ( is_object( $details ) ) {
$details = get_object_vars( $details );
}
$site = wp_update_site( $blog_id, $details );
if ( is_wp_error( $site ) ) {
return false;
}
return true;
}
/**
* Cleans the site details cache for a site.
*
* @since 4.7.4
*
* @param int $site_id Optional. Site ID. Default is the current site ID.
*/
function clean_site_details_cache( $site_id = 0 ) {
$site_id = (int) $site_id;
if ( ! $site_id ) {
$site_id = get_current_blog_id();
}
wp_cache_delete( $site_id, 'site-details' );
wp_cache_delete( $site_id, 'blog-details' );
}
/**
* Retrieves option value for a given blog id based on name of option.
*
* If the option does not exist or does not have a value, then the return value
* will be false. This is useful to check whether you need to install an option
* and is commonly used during installation of plugin options and to test
* whether upgrading is required.
*
* If the option was serialized then it will be unserialized when it is returned.
*
* @since MU (3.0.0)
*
* @param int $id A blog ID. Can be null to refer to the current blog.
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
* @param mixed $default_value Optional. Default value to return if the option does not exist.
* @return mixed Value set for the option.
*/
function get_blog_option( $id, $option, $default_value = false ) {
$id = (int) $id;
if ( empty( $id ) ) {
$id = get_current_blog_id();
}
if ( get_current_blog_id() === $id ) {
return get_option( $option, $default_value );
}
switch_to_blog( $id );
$value = get_option( $option, $default_value );
restore_current_blog();
/**
* Filters a blog option value.
*
* The dynamic portion of the hook name, `$option`, refers to the blog option name.
*
* @since 3.5.0
*
* @param string $value The option value.
* @param int $id Blog ID.
*/
return apply_filters( "blog_option_{$option}", $value, $id );
}
/**
* Adds a new option for a given blog ID.
*
* You do not need to serialize values. If the value needs to be serialized, then
* it will be serialized before it is inserted into the database. Remember,
* resources can not be serialized or added as an option.
*
* You can create options without values and then update the values later.
* Existing options will not be updated and checks are performed to ensure that you
* aren't adding a protected WordPress option. Care should be taken to not name
* options the same as the ones which are protected.
*
* @since MU (3.0.0)
*
* @param int $id A blog ID. Can be null to refer to the current blog.
* @param string $option Name of option to add. Expected to not be SQL-escaped.
* @param mixed $value Option value, can be anything. Expected to not be SQL-escaped.
* @return bool True if the option was added, false otherwise.
*/
function add_blog_option( $id, $option, $value ) {
$id = (int) $id;
if ( empty( $id ) ) {
$id = get_current_blog_id();
}
if ( get_current_blog_id() === $id ) {
return add_option( $option, $value );
}
switch_to_blog( $id );
$return = add_option( $option, $value );
restore_current_blog();
return $return;
}
/**
* Removes an option by name for a given blog ID. Prevents removal of protected WordPress options.
*
* @since MU (3.0.0)
*
* @param int $id A blog ID. Can be null to refer to the current blog.
* @param string $option Name of option to remove. Expected to not be SQL-escaped.
* @return bool True if the option was deleted, false otherwise.
*/
function delete_blog_option( $id, $option ) {
$id = (int) $id;
if ( empty( $id ) ) {
$id = get_current_blog_id();
}
if ( get_current_blog_id() === $id ) {
return delete_option( $option );
}
switch_to_blog( $id );
$return = delete_option( $option );
restore_current_blog();
return $return;
}
/**
* Updates an option for a particular blog.
*
* @since MU (3.0.0)
*
* @param int $id The blog ID.
* @param string $option The option key.
* @param mixed $value The option value.
* @param mixed $deprecated Not used.
* @return bool True if the value was updated, false otherwise.
*/
function update_blog_option( $id, $option, $value, $deprecated = null ) {
$id = (int) $id;
if ( null !== $deprecated ) {
_deprecated_argument( __FUNCTION__, '3.1.0' );
}
if ( get_current_blog_id() === $id ) {
return update_option( $option, $value );
}
switch_to_blog( $id );
$return = update_option( $option, $value );
restore_current_blog();
return $return;
}
/**
* Switches the current blog.
*
* This function is useful if you need to pull posts, or other information,
* from other blogs. You can switch back afterwards using restore_current_blog().
*
* PHP code loaded with the originally requested site, such as code from a plugin or theme, does not switch. See #14941.
*
* @see restore_current_blog()
* @since MU (3.0.0)
*
* @global wpdb $wpdb WordPress database abstraction object.
* @global int $blog_id
* @global array $_wp_switched_stack
* @global bool $switched
* @global string $table_prefix The database table prefix.
* @global WP_Object_Cache $wp_object_cache
*
* @param int $new_blog_id The ID of the blog to switch to. Default: current blog.
* @param bool $deprecated Not used.
* @return true Always returns true.
*/
function switch_to_blog( $new_blog_id, $deprecated = null ) {
global $wpdb;
$prev_blog_id = get_current_blog_id();
if ( empty( $new_blog_id ) ) {
$new_blog_id = $prev_blog_id;
}
$GLOBALS['_wp_switched_stack'][] = $prev_blog_id;
/*
* If we're switching to the same blog id that we're on,
* set the right vars, do the associated actions, but skip
* the extra unnecessary work
*/
if ( $new_blog_id === $prev_blog_id ) {
/**
* Fires when the blog is switched.
*
* @since MU (3.0.0)
* @since 5.4.0 The `$context` parameter was added.
*
* @param int $new_blog_id New blog ID.
* @param int $prev_blog_id Previous blog ID.
* @param string $context Additional context. Accepts 'switch' when called from switch_to_blog()
* or 'restore' when called from restore_current_blog().
*/
do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'switch' );
$GLOBALS['switched'] = true;
return true;
}
$wpdb->set_blog_id( $new_blog_id );
$GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();
$GLOBALS['blog_id'] = $new_blog_id;
if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
wp_cache_switch_to_blog( $new_blog_id );
} else {
global $wp_object_cache;
if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
$global_groups = $wp_object_cache->global_groups;
} else {
$global_groups = false;
}
wp_cache_init();
if ( function_exists( 'wp_cache_add_global_groups' ) ) {
if ( is_array( $global_groups ) ) {
wp_cache_add_global_groups( $global_groups );
} else {
wp_cache_add_global_groups(
array(
'blog-details',
'blog-id-cache',
'blog-lookup',
'blog_meta',
'global-posts',
'image_editor',
'networks',
'network-queries',
'sites',
'site-details',
'site-options',
'site-queries',
'site-transient',
'theme_files',
'rss',
'users',
'user-queries',
'user_meta',
'useremail',
'userlogins',
'userslugs',
)
);
}
wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) );
}
}
/** This filter is documented in wp-includes/ms-blogs.php */
do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'switch' );
$GLOBALS['switched'] = true;
return true;
}
/**
* Restores the current blog, after calling switch_to_blog().
*
* @see switch_to_blog()
* @since MU (3.0.0)
*
* @global wpdb $wpdb WordPress database abstraction object.
* @global array $_wp_switched_stack
* @global int $blog_id
* @global bool $switched
* @global string $table_prefix The database table prefix.
* @global WP_Object_Cache $wp_object_cache
*
* @return bool True on success, false if we're already on the current blog.
*/
function restore_current_blog() {
global $wpdb;
if ( empty( $GLOBALS['_wp_switched_stack'] ) ) {
return false;
}
$new_blog_id = array_pop( $GLOBALS['_wp_switched_stack'] );
$prev_blog_id = get_current_blog_id();
if ( $new_blog_id === $prev_blog_id ) {
/** This filter is documented in wp-includes/ms-blogs.php */
do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'restore' );
// If we still have items in the switched stack, consider ourselves still 'switched'.
$GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );
return true;
}
$wpdb->set_blog_id( $new_blog_id );
$GLOBALS['blog_id'] = $new_blog_id;
$GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();
if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
wp_cache_switch_to_blog( $new_blog_id );
} else {
global $wp_object_cache;
if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
$global_groups = $wp_object_cache->global_groups;
} else {
$global_groups = false;
}
wp_cache_init();
if ( function_exists( 'wp_cache_add_global_groups' ) ) {
if ( is_array( $global_groups ) ) {
wp_cache_add_global_groups( $global_groups );
} else {
wp_cache_add_global_groups(
array(
'blog-details',
'blog-id-cache',
'blog-lookup',
'blog_meta',
'global-posts',
'image_editor',
'networks',
'network-queries',
'sites',
'site-details',
'site-options',
'site-queries',
'site-transient',
'theme_files',
'rss',
'users',
'user-queries',
'user_meta',
'useremail',
'userlogins',
'userslugs',
)
);
}
wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) );
}
}
/** This filter is documented in wp-includes/ms-blogs.php */
do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'restore' );
// If we still have items in the switched stack, consider ourselves still 'switched'.
$GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );
return true;
}
/**
* Switches the initialized roles and current user capabilities to another site.
*
* @since 4.9.0
*
* @param int $new_site_id New site ID.
* @param int $old_site_id Old site ID.
*/
function wp_switch_roles_and_user( $new_site_id, $old_site_id ) {
if ( $new_site_id === $old_site_id ) {
return;
}
if ( ! did_action( 'init' ) ) {
return;
}
wp_roles()->for_site( $new_site_id );
wp_get_current_user()->for_site( $new_site_id );
}
/**
* Determines if switch_to_blog() is in effect.
*
* @since 3.5.0
*
* @global array $_wp_switched_stack
*
* @return bool True if switched, false otherwise.
*/
function ms_is_switched() {
return ! empty( $GLOBALS['_wp_switched_stack'] );
}
/**
* Checks if a particular blog is archived.
*
* @since MU (3.0.0)
*
* @param int $id Blog ID.
* @return string Whether the blog is archived or not.
*/
function is_archived( $id ) {
return get_blog_status( $id, 'archived' );
}
/**
* Updates the 'archived' status of a particular blog.
*
* @since MU (3.0.0)
*
* @param int $id Blog ID.
* @param string $archived The new status.
* @return string $archived
*/
function update_archived( $id, $archived ) {
update_blog_status( $id, 'archived', $archived );
return $archived;
}
/**
* Updates a blog details field.
*
* @since MU (3.0.0)
* @since 5.1.0 Use wp_update_site() internally.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $blog_id Blog ID.
* @param string $pref Field name.
* @param string $value Field value.
* @param null $deprecated Not used.
* @return string|false $value
*/
function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) {
global $wpdb;
if ( null !== $deprecated ) {
_deprecated_argument( __FUNCTION__, '3.1.0' );
}
$allowed_field_names = array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
if ( ! in_array( $pref, $allowed_field_names, true ) ) {
return $value;
}
$result = wp_update_site(
$blog_id,
array(
$pref => $value,
)
);
if ( is_wp_error( $result ) ) {
return false;
}
return $value;
}
/**
* Gets a blog details field.
*
* @since MU (3.0.0)
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $id Blog ID.
* @param string $pref Field name.
* @return bool|string|null $value
*/
function get_blog_status( $id, $pref ) {
global $wpdb;
$details = get_site( $id );
if ( $details ) {
return $details->$pref;
}
return $wpdb->get_var( $wpdb->prepare( "SELECT %s FROM {$wpdb->blogs} WHERE blog_id = %d", $pref, $id ) );
}
/**
* Gets a list of most recently updated blogs.
*
* @since MU (3.0.0)
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param mixed $deprecated Not used.
* @param int $start Optional. Number of blogs to offset the query. Used to build LIMIT clause.
* Can be used for pagination. Default 0.
* @param int $quantity Optional. The maximum number of blogs to retrieve. Default 40.
* @return array The list of blogs.
*/
function get_last_updated( $deprecated = '', $start = 0, $quantity = 40 ) {
global $wpdb;
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, 'MU' ); // Never used.
}
return $wpdb->get_results( $wpdb->prepare( "SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' AND last_updated != '0000-00-00 00:00:00' ORDER BY last_updated DESC limit %d, %d", get_current_network_id(), $start, $quantity ), ARRAY_A );
}
/**
* Handler for updating the site's last updated date when a post is published or
* an already published post is changed.
*
* @since 3.3.0
*
* @param string $new_status The new post status.
* @param string $old_status The old post status.
* @param WP_Post $post Post object.
*/
function _update_blog_date_on_post_publish( $new_status, $old_status, $post ) {
$post_type_obj = get_post_type_object( $post->post_type );
if ( ! $post_type_obj || ! $post_type_obj->public ) {
return;
}
if ( 'publish' !== $new_status && 'publish' !== $old_status ) {
return;
}
// Post was freshly published, published post was saved, or published post was unpublished.
wpmu_update_blogs_date();
}
/**
* Handler for updating the current site's last updated date when a published
* post is deleted.
*
* @since 3.4.0
*
* @param int $post_id Post ID
*/
function _update_blog_date_on_post_delete( $post_id ) {
$post = get_post( $post_id );
$post_type_obj = get_post_type_object( $post->post_type );
if ( ! $post_type_obj || ! $post_type_obj->public ) {
return;
}
if ( 'publish' !== $post->post_status ) {
return;
}
wpmu_update_blogs_date();
}
/**
* Handler for updating the current site's posts count when a post is deleted.
*
* @since 4.0.0
* @since 6.2.0 Added the `$post` parameter.
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
function _update_posts_count_on_delete( $post_id, $post ) {
if ( ! $post || 'publish' !== $post->post_status || 'post' !== $post->post_type ) {
return;
}
update_posts_count();
}
/**
* Handler for updating the current site's posts count when a post status changes.
*
* @since 4.0.0
* @since 4.9.0 Added the `$post` parameter.
*
* @param string $new_status The status the post is changing to.
* @param string $old_status The status the post is changing from.
* @param WP_Post $post Post object
*/
function _update_posts_count_on_transition_post_status( $new_status, $old_status, $post = null ) {
if ( $new_status === $old_status ) {
return;
}
if ( 'post' !== get_post_type( $post ) ) {
return;
}
if ( 'publish' !== $new_status && 'publish' !== $old_status ) {
return;
}
update_posts_count();
}
/**
* Counts number of sites grouped by site status.
*
* @since 5.3.0
*
* @param int $network_id Optional. The network to get counts for. Default is the current network ID.
* @return int[] {
* Numbers of sites grouped by site status.
*
* @type int $all The total number of sites.
* @type int $public The number of public sites.
* @type int $archived The number of archived sites.
* @type int $mature The number of mature sites.
* @type int $spam The number of spam sites.
* @type int $deleted The number of deleted sites.
* }
*/
function wp_count_sites( $network_id = null ) {
if ( empty( $network_id ) ) {
$network_id = get_current_network_id();
}
$counts = array();
$args = array(
'network_id' => $network_id,
'number' => 1,
'fields' => 'ids',
'no_found_rows' => false,
);
$q = new WP_Site_Query( $args );
$counts['all'] = $q->found_sites;
$_args = $args;
$statuses = array( 'public', 'archived', 'mature', 'spam', 'deleted' );
foreach ( $statuses as $status ) {
$_args = $args;
$_args[ $status ] = 1;
$q = new WP_Site_Query( $_args );
$counts[ $status ] = $q->found_sites;
}
return $counts;
}
<?php
/**
* User API: WP_User_Query class
*
* @package WordPress
* @subpackage Users
* @since 4.4.0
*/
/**
* Core class used for querying users.
*
* @since 3.1.0
*
* @see WP_User_Query::prepare_query() for information on accepted arguments.
*/
#[AllowDynamicProperties]
class WP_User_Query {
/**
* Query vars, after parsing
*
* @since 3.5.0
* @var array
*/
public $query_vars = array();
/**
* List of found user IDs.
*
* @since 3.1.0
* @var array
*/
private $results;
/**
* Total number of found users for the current query
*
* @since 3.1.0
* @var int
*/
private $total_users = 0;
/**
* Metadata query container.
*
* @since 4.2.0
* @var WP_Meta_Query
*/
public $meta_query = false;
/**
* The SQL query used to fetch matching users.
*
* @since 4.4.0
* @var string
*/
public $request;
private $compat_fields = array( 'results', 'total_users' );
// SQL clauses.
public $query_fields;
public $query_from;
public $query_where;
public $query_orderby;
public $query_limit;
/**
* Constructor.
*
* @since 3.1.0
*
* @param null|string|array $query Optional. The query variables.
* See WP_User_Query::prepare_query() for information on accepted arguments.
*/
public function __construct( $query = null ) {
if ( ! empty( $query ) ) {
$this->prepare_query( $query );
$this->query();
}
}
/**
* Fills in missing query variables with default values.
*
* @since 4.4.0
*
* @param string|array $args Query vars, as passed to `WP_User_Query`.
* @return array Complete query variables with undefined ones filled in with defaults.
*/
public static function fill_query_vars( $args ) {
$defaults = array(
'blog_id' => get_current_blog_id(),
'role' => '',
'role__in' => array(),
'role__not_in' => array(),
'capability' => '',
'capability__in' => array(),
'capability__not_in' => array(),
'meta_key' => '',
'meta_value' => '',
'meta_compare' => '',
'include' => array(),
'exclude' => array(),
'search' => '',
'search_columns' => array(),
'orderby' => 'login',
'order' => 'ASC',
'offset' => '',
'number' => '',
'paged' => 1,
'count_total' => true,
'fields' => 'all',
'who' => '',
'has_published_posts' => null,
'nicename' => '',
'nicename__in' => array(),
'nicename__not_in' => array(),
'login' => '',
'login__in' => array(),
'login__not_in' => array(),
'cache_results' => true,
);
return wp_parse_args( $args, $defaults );
}
/**
* Prepares the query variables.
*
* @since 3.1.0
* @since 4.1.0 Added the ability to order by the `include` value.
* @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax
* for `$orderby` parameter.
* @since 4.3.0 Added 'has_published_posts' parameter.
* @since 4.4.0 Added 'paged', 'role__in', and 'role__not_in' parameters. The 'role' parameter was updated to
* permit an array or comma-separated list of values. The 'number' parameter was updated to support
* querying for all users with using -1.
* @since 4.7.0 Added 'nicename', 'nicename__in', 'nicename__not_in', 'login', 'login__in',
* and 'login__not_in' parameters.
* @since 5.1.0 Introduced the 'meta_compare_key' parameter.
* @since 5.3.0 Introduced the 'meta_type_key' parameter.
* @since 5.9.0 Added 'capability', 'capability__in', and 'capability__not_in' parameters.
* Deprecated the 'who' parameter.
* @since 6.3.0 Added 'cache_results' parameter.
*
* @global wpdb $wpdb WordPress database abstraction object.
* @global WP_Roles $wp_roles WordPress role management object.
*
* @param string|array $query {
* Optional. Array or string of query parameters.
*
* @type int $blog_id The site ID. Default is the current site.
* @type string|string[] $role An array or a comma-separated list of role names that users
* must match to be included in results. Note that this is
* an inclusive list: users must match *each* role. Default empty.
* @type string[] $role__in An array of role names. Matched users must have at least one
* of these roles. Default empty array.
* @type string[] $role__not_in An array of role names to exclude. Users matching one or more
* of these roles will not be included in results. Default empty array.
* @type string|string[] $meta_key Meta key or keys to filter by.
* @type string|string[] $meta_value Meta value or values to filter by.
* @type string $meta_compare MySQL operator used for comparing the meta value.
* See WP_Meta_Query::__construct() for accepted values and default value.
* @type string $meta_compare_key MySQL operator used for comparing the meta key.
* See WP_Meta_Query::__construct() for accepted values and default value.
* @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons.
* See WP_Meta_Query::__construct() for accepted values and default value.
* @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons.
* See WP_Meta_Query::__construct() for accepted values and default value.
* @type array $meta_query An associative array of WP_Meta_Query arguments.
* See WP_Meta_Query::__construct() for accepted values.
* @type string|string[] $capability An array or a comma-separated list of capability names that users
* must match to be included in results. Note that this is
* an inclusive list: users must match *each* capability.
* Does NOT work for capabilities not in the database or filtered
* via {@see 'map_meta_cap'}. Default empty.
* @type string[] $capability__in An array of capability names. Matched users must have at least one
* of these capabilities.
* Does NOT work for capabilities not in the database or filtered
* via {@see 'map_meta_cap'}. Default empty array.
* @type string[] $capability__not_in An array of capability names to exclude. Users matching one or more
* of these capabilities will not be included in results.
* Does NOT work for capabilities not in the database or filtered
* via {@see 'map_meta_cap'}. Default empty array.
* @type int[] $include An array of user IDs to include. Default empty array.
* @type int[] $exclude An array of user IDs to exclude. Default empty array.
* @type string $search Search keyword. Searches for possible string matches on columns.
* When `$search_columns` is left empty, it tries to determine which
* column to search in based on search string. Default empty.
* @type string[] $search_columns Array of column names to be searched. Accepts 'ID', 'user_login',
* 'user_email', 'user_url', 'user_nicename', 'display_name'.
* Default empty array.
* @type string|array $orderby Field(s) to sort the retrieved users by. May be a single value,
* an array of values, or a multi-dimensional array with fields as
* keys and orders ('ASC' or 'DESC') as values. Accepted values are:
* - 'ID'
* - 'display_name' (or 'name')
* - 'include'
* - 'user_login' (or 'login')
* - 'login__in'
* - 'user_nicename' (or 'nicename')
* - 'nicename__in'
* - 'user_email' (or 'email')
* - 'user_url' (or 'url')
* - 'user_registered' (or 'registered')
* - 'post_count'
* - 'meta_value'
* - 'meta_value_num'
* - The value of `$meta_key`
* - An array key of `$meta_query`
* To use 'meta_value' or 'meta_value_num', `$meta_key`
* must be also be defined. Default 'user_login'.
* @type string $order Designates ascending or descending order of users. Order values
* passed as part of an `$orderby` array take precedence over this
* parameter. Accepts 'ASC', 'DESC'. Default 'ASC'.
* @type int $offset Number of users to offset in retrieved results. Can be used in
* conjunction with pagination. Default 0.
* @type int $number Number of users to limit the query for. Can be used in
* conjunction with pagination. Value -1 (all) is supported, but
* should be used with caution on larger sites.
* Default -1 (all users).
* @type int $paged When used with number, defines the page of results to return.
* Default 1.
* @type bool $count_total Whether to count the total number of users found. If pagination
* is not needed, setting this to false can improve performance.
* Default true.
* @type string|string[] $fields Which fields to return. Single or all fields (string), or array
* of fields. Accepts:
* - 'ID'
* - 'display_name'
* - 'user_login'
* - 'user_nicename'
* - 'user_email'
* - 'user_url'
* - 'user_registered'
* - 'user_pass'
* - 'user_activation_key'
* - 'user_status'
* - 'spam' (only available on multisite installs)
* - 'deleted' (only available on multisite installs)
* - 'all' for all fields and loads user meta.
* - 'all_with_meta' Deprecated. Use 'all'.
* Default 'all'.
* @type string $who Deprecated, use `$capability` instead.
* Type of users to query. Accepts 'authors'.
* Default empty (all users).
* @type bool|string[] $has_published_posts Pass an array of post types to filter results to users who have
* published posts in those post types. `true` is an alias for all
* public post types.
* @type string $nicename The user nicename. Default empty.
* @type string[] $nicename__in An array of nicenames to include. Users matching one of these
* nicenames will be included in results. Default empty array.
* @type string[] $nicename__not_in An array of nicenames to exclude. Users matching one of these
* nicenames will not be included in results. Default empty array.
* @type string $login The user login. Default empty.
* @type string[] $login__in An array of logins to include. Users matching one of these
* logins will be included in results. Default empty array.
* @type string[] $login__not_in An array of logins to exclude. Users matching one of these
* logins will not be included in results. Default empty array.
* @type bool $cache_results Whether to cache user information. Default true.
* }
*/
public function prepare_query( $query = array() ) {
global $wpdb, $wp_roles;
if ( empty( $this->query_vars ) || ! empty( $query ) ) {
$this->query_limit = null;
$this->query_vars = $this->fill_query_vars( $query );
}
/**
* Fires before the WP_User_Query has been parsed.
*
* The passed WP_User_Query object contains the query variables,
* not yet passed into SQL.
*
* @since 4.0.0
*
* @param WP_User_Query $query Current instance of WP_User_Query (passed by reference).
*/
do_action_ref_array( 'pre_get_users', array( &$this ) );
// Ensure that query vars are filled after 'pre_get_users'.
$qv =& $this->query_vars;
$qv = $this->fill_query_vars( $qv );
$allowed_fields = array(
'id',
'user_login',
'user_pass',
'user_nicename',
'user_email',
'user_url',
'user_registered',
'user_activation_key',
'user_status',
'display_name',
);
if ( is_multisite() ) {
$allowed_fields[] = 'spam';
$allowed_fields[] = 'deleted';
}
if ( is_array( $qv['fields'] ) ) {
$qv['fields'] = array_map( 'strtolower', $qv['fields'] );
$qv['fields'] = array_intersect( array_unique( $qv['fields'] ), $allowed_fields );
if ( empty( $qv['fields'] ) ) {
$qv['fields'] = array( 'id' );
}
$this->query_fields = array();
foreach ( $qv['fields'] as $field ) {
$field = 'id' === $field ? 'ID' : sanitize_key( $field );
$this->query_fields[] = "$wpdb->users.$field";
}
$this->query_fields = implode( ',', $this->query_fields );
} elseif ( 'all_with_meta' === $qv['fields'] || 'all' === $qv['fields'] || ! in_array( $qv['fields'], $allowed_fields, true ) ) {
$this->query_fields = "$wpdb->users.ID";
} else {
$field = 'id' === strtolower( $qv['fields'] ) ? 'ID' : sanitize_key( $qv['fields'] );
$this->query_fields = "$wpdb->users.$field";
}
if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
$this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
}
$this->query_from = "FROM $wpdb->users";
$this->query_where = 'WHERE 1=1';
// Parse and sanitize 'include', for use by 'orderby' as well as 'include' below.
if ( ! empty( $qv['include'] ) ) {
$include = wp_parse_id_list( $qv['include'] );
} else {
$include = false;
}
$blog_id = 0;
if ( isset( $qv['blog_id'] ) ) {
$blog_id = absint( $qv['blog_id'] );
}
if ( $qv['has_published_posts'] && $blog_id ) {
if ( true === $qv['has_published_posts'] ) {
$post_types = get_post_types( array( 'public' => true ) );
} else {
$post_types = (array) $qv['has_published_posts'];
}
foreach ( $post_types as &$post_type ) {
$post_type = $wpdb->prepare( '%s', $post_type );
}
$posts_table = $wpdb->get_blog_prefix( $blog_id ) . 'posts';
$this->query_where .= " AND $wpdb->users.ID IN ( SELECT DISTINCT $posts_table.post_author FROM $posts_table WHERE $posts_table.post_status = 'publish' AND $posts_table.post_type IN ( " . implode( ', ', $post_types ) . ' ) )';
}
// nicename
if ( '' !== $qv['nicename'] ) {
$this->query_where .= $wpdb->prepare( ' AND user_nicename = %s', $qv['nicename'] );
}
if ( ! empty( $qv['nicename__in'] ) ) {
$sanitized_nicename__in = array_map( 'esc_sql', $qv['nicename__in'] );
$nicename__in = implode( "','", $sanitized_nicename__in );
$this->query_where .= " AND user_nicename IN ( '$nicename__in' )";
}
if ( ! empty( $qv['nicename__not_in'] ) ) {
$sanitized_nicename__not_in = array_map( 'esc_sql', $qv['nicename__not_in'] );
$nicename__not_in = implode( "','", $sanitized_nicename__not_in );
$this->query_where .= " AND user_nicename NOT IN ( '$nicename__not_in' )";
}
// login
if ( '' !== $qv['login'] ) {
$this->query_where .= $wpdb->prepare( ' AND user_login = %s', $qv['login'] );
}
if ( ! empty( $qv['login__in'] ) ) {
$sanitized_login__in = array_map( 'esc_sql', $qv['login__in'] );
$login__in = implode( "','", $sanitized_login__in );
$this->query_where .= " AND user_login IN ( '$login__in' )";
}
if ( ! empty( $qv['login__not_in'] ) ) {
$sanitized_login__not_in = array_map( 'esc_sql', $qv['login__not_in'] );
$login__not_in = implode( "','", $sanitized_login__not_in );
$this->query_where .= " AND user_login NOT IN ( '$login__not_in' )";
}
// Meta query.
$this->meta_query = new WP_Meta_Query();
$this->meta_query->parse_query_vars( $qv );
if ( isset( $qv['who'] ) && 'authors' === $qv['who'] && $blog_id ) {
_deprecated_argument(
'WP_User_Query',
'5.9.0',
sprintf(
/* translators: 1: who, 2: capability */
__( '%1$s is deprecated. Use %2$s instead.' ),
'<code>who</code>',
'<code>capability</code>'
)
);
$who_query = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'user_level',
'value' => 0,
'compare' => '!=',
);
// Prevent extra meta query.
$qv['blog_id'] = 0;
$blog_id = 0;
if ( empty( $this->meta_query->queries ) ) {
$this->meta_query->queries = array( $who_query );
} else {
// Append the cap query to the original queries and reparse the query.
$this->meta_query->queries = array(
'relation' => 'AND',
array( $this->meta_query->queries, $who_query ),
);
}
$this->meta_query->parse_query_vars( $this->meta_query->queries );
}
// Roles.
$roles = array();
if ( isset( $qv['role'] ) ) {
if ( is_array( $qv['role'] ) ) {
$roles = $qv['role'];
} elseif ( is_string( $qv['role'] ) && ! empty( $qv['role'] ) ) {
$roles = array_map( 'trim', explode( ',', $qv['role'] ) );
}
}
$role__in = array();
if ( isset( $qv['role__in'] ) ) {
$role__in = (array) $qv['role__in'];
}
$role__not_in = array();
if ( isset( $qv['role__not_in'] ) ) {
$role__not_in = (array) $qv['role__not_in'];
}
// Capabilities.
$available_roles = array();
if ( ! empty( $qv['capability'] ) || ! empty( $qv['capability__in'] ) || ! empty( $qv['capability__not_in'] ) ) {
$wp_roles->for_site( $blog_id );
$available_roles = $wp_roles->roles;
}
$capabilities = array();
if ( ! empty( $qv['capability'] ) ) {
if ( is_array( $qv['capability'] ) ) {
$capabilities = $qv['capability'];
} elseif ( is_string( $qv['capability'] ) ) {
$capabilities = array_map( 'trim', explode( ',', $qv['capability'] ) );
}
}
$capability__in = array();
if ( ! empty( $qv['capability__in'] ) ) {
$capability__in = (array) $qv['capability__in'];
}
$capability__not_in = array();
if ( ! empty( $qv['capability__not_in'] ) ) {
$capability__not_in = (array) $qv['capability__not_in'];
}
// Keep track of all capabilities and the roles they're added on.
$caps_with_roles = array();
foreach ( $available_roles as $role => $role_data ) {
$role_caps = array_keys( array_filter( $role_data['capabilities'] ) );
foreach ( $capabilities as $cap ) {
if ( in_array( $cap, $role_caps, true ) ) {
$caps_with_roles[ $cap ][] = $role;
break;
}
}
foreach ( $capability__in as $cap ) {
if ( in_array( $cap, $role_caps, true ) ) {
$role__in[] = $role;
break;
}
}
foreach ( $capability__not_in as $cap ) {
if ( in_array( $cap, $role_caps, true ) ) {
$role__not_in[] = $role;
break;
}
}
}
$role__in = array_merge( $role__in, $capability__in );
$role__not_in = array_merge( $role__not_in, $capability__not_in );
$roles = array_unique( $roles );
$role__in = array_unique( $role__in );
$role__not_in = array_unique( $role__not_in );
// Support querying by capabilities added directly to users.
if ( $blog_id && ! empty( $capabilities ) ) {
$capabilities_clauses = array( 'relation' => 'AND' );
foreach ( $capabilities as $cap ) {
$clause = array( 'relation' => 'OR' );
$clause[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'value' => '"' . $cap . '"',
'compare' => 'LIKE',
);
if ( ! empty( $caps_with_roles[ $cap ] ) ) {
foreach ( $caps_with_roles[ $cap ] as $role ) {
$clause[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'value' => '"' . $role . '"',
'compare' => 'LIKE',
);
}
}
$capabilities_clauses[] = $clause;
}
$role_queries[] = $capabilities_clauses;
if ( empty( $this->meta_query->queries ) ) {
$this->meta_query->queries[] = $capabilities_clauses;
} else {
// Append the cap query to the original queries and reparse the query.
$this->meta_query->queries = array(
'relation' => 'AND',
array( $this->meta_query->queries, array( $capabilities_clauses ) ),
);
}
$this->meta_query->parse_query_vars( $this->meta_query->queries );
}
if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) {
$role_queries = array();
$roles_clauses = array( 'relation' => 'AND' );
if ( ! empty( $roles ) ) {
foreach ( $roles as $role ) {
$roles_clauses[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'value' => '"' . $role . '"',
'compare' => 'LIKE',
);
}
$role_queries[] = $roles_clauses;
}
$role__in_clauses = array( 'relation' => 'OR' );
if ( ! empty( $role__in ) ) {
foreach ( $role__in as $role ) {
$role__in_clauses[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'value' => '"' . $role . '"',
'compare' => 'LIKE',
);
}
$role_queries[] = $role__in_clauses;
}
$role__not_in_clauses = array( 'relation' => 'AND' );
if ( ! empty( $role__not_in ) ) {
foreach ( $role__not_in as $role ) {
$role__not_in_clauses[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'value' => '"' . $role . '"',
'compare' => 'NOT LIKE',
);
}
$role_queries[] = $role__not_in_clauses;
}
// If there are no specific roles named, make sure the user is a member of the site.
if ( empty( $role_queries ) ) {
$role_queries[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'compare' => 'EXISTS',
);
}
// Specify that role queries should be joined with AND.
$role_queries['relation'] = 'AND';
if ( empty( $this->meta_query->queries ) ) {
$this->meta_query->queries = $role_queries;
} else {
// Append the cap query to the original queries and reparse the query.
$this->meta_query->queries = array(
'relation' => 'AND',
array( $this->meta_query->queries, $role_queries ),
);
}
$this->meta_query->parse_query_vars( $this->meta_query->queries );
}
if ( ! empty( $this->meta_query->queries ) ) {
$clauses = $this->meta_query->get_sql( 'user', $wpdb->users, 'ID', $this );
$this->query_from .= $clauses['join'];
$this->query_where .= $clauses['where'];
if ( $this->meta_query->has_or_relation() ) {
$this->query_fields = 'DISTINCT ' . $this->query_fields;
}
}
// Sorting.
$qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : '';
$order = $this->parse_order( $qv['order'] );
if ( empty( $qv['orderby'] ) ) {
// Default order is by 'user_login'.
$ordersby = array( 'user_login' => $order );
} elseif ( is_array( $qv['orderby'] ) ) {
$ordersby = $qv['orderby'];
} else {
// 'orderby' values may be a comma- or space-separated list.
$ordersby = preg_split( '/[,\s]+/', $qv['orderby'] );
}
$orderby_array = array();
foreach ( $ordersby as $_key => $_value ) {
if ( ! $_value ) {
continue;
}
if ( is_int( $_key ) ) {
// Integer key means this is a flat array of 'orderby' fields.
$_orderby = $_value;
$_order = $order;
} else {
// Non-integer key means this the key is the field and the value is ASC/DESC.
$_orderby = $_key;
$_order = $_value;
}
$parsed = $this->parse_orderby( $_orderby );
if ( ! $parsed ) {
continue;
}
if ( 'nicename__in' === $_orderby || 'login__in' === $_orderby ) {
$orderby_array[] = $parsed;
} else {
$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
}
}
// If no valid clauses were found, order by user_login.
if ( empty( $orderby_array ) ) {
$orderby_array[] = "user_login $order";
}
$this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array );
// Limit.
if ( isset( $qv['number'] ) && $qv['number'] > 0 ) {
if ( $qv['offset'] ) {
$this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $qv['offset'], $qv['number'] );
} else {
$this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $qv['number'] * ( $qv['paged'] - 1 ), $qv['number'] );
}
}
$search = '';
if ( isset( $qv['search'] ) ) {
$search = trim( $qv['search'] );
}
if ( $search ) {
$leading_wild = ( ltrim( $search, '*' ) !== $search );
$trailing_wild = ( rtrim( $search, '*' ) !== $search );
if ( $leading_wild && $trailing_wild ) {
$wild = 'both';
} elseif ( $leading_wild ) {
$wild = 'leading';
} elseif ( $trailing_wild ) {
$wild = 'trailing';
} else {
$wild = false;
}
if ( $wild ) {
$search = trim( $search, '*' );
}
$search_columns = array();
if ( $qv['search_columns'] ) {
$search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename', 'display_name' ) );
}
if ( ! $search_columns ) {
if ( str_contains( $search, '@' ) ) {
$search_columns = array( 'user_email' );
} elseif ( is_numeric( $search ) ) {
$search_columns = array( 'user_login', 'ID' );
} elseif ( preg_match( '|^https?://|', $search ) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) ) {
$search_columns = array( 'user_url' );
} else {
$search_columns = array( 'user_login', 'user_url', 'user_email', 'user_nicename', 'display_name' );
}
}
/**
* Filters the columns to search in a WP_User_Query search.
*
* The default columns depend on the search term, and include 'ID', 'user_login',
* 'user_email', 'user_url', 'user_nicename', and 'display_name'.
*
* @since 3.6.0
*
* @param string[] $search_columns Array of column names to be searched.
* @param string $search Text being searched.
* @param WP_User_Query $query The current WP_User_Query instance.
*/
$search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this );
$this->query_where .= $this->get_search_sql( $search, $search_columns, $wild );
}
if ( ! empty( $include ) ) {
// Sanitized earlier.
$ids = implode( ',', $include );
$this->query_where .= " AND $wpdb->users.ID IN ($ids)";
} elseif ( ! empty( $qv['exclude'] ) ) {
$ids = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
$this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)";
}
// Date queries are allowed for the user_registered field.
if ( ! empty( $qv['date_query'] ) && is_array( $qv['date_query'] ) ) {
$date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' );
$this->query_where .= $date_query->get_sql();
}
/**
* Fires after the WP_User_Query has been parsed, and before
* the query is executed.
*
* The passed WP_User_Query object contains SQL parts formed
* from parsing the given query.
*
* @since 3.1.0
*
* @param WP_User_Query $query Current instance of WP_User_Query (passed by reference).
*/
do_action_ref_array( 'pre_user_query', array( &$this ) );
}
/**
* Executes the query, with the current variables.
*
* @since 3.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*/
public function query() {
global $wpdb;
if ( ! did_action( 'plugins_loaded' ) ) {
_doing_it_wrong(
'WP_User_Query::query',
sprintf(
/* translators: %s: plugins_loaded */
__( 'User queries should not be run before the %s hook.' ),
'<code>plugins_loaded</code>'
),
'6.1.1'
);
}
$qv =& $this->query_vars;
// Do not cache results if more than 3 fields are requested.
if ( is_array( $qv['fields'] ) && count( $qv['fields'] ) > 3 ) {
$qv['cache_results'] = false;
}
/**
* Filters the users array before the query takes place.
*
* Return a non-null value to bypass WordPress' default user queries.
*
* Filtering functions that require pagination information are encouraged to set
* the `total_users` property of the WP_User_Query object, passed to the filter
* by reference. If WP_User_Query does not perform a database query, it will not
* have enough information to generate these values itself.
*
* @since 5.1.0
*
* @param array|null $results Return an array of user data to short-circuit WP's user query
* or null to allow WP to run its normal queries.
* @param WP_User_Query $query The WP_User_Query instance (passed by reference).
*/
$this->results = apply_filters_ref_array( 'users_pre_query', array( null, &$this ) );
if ( null === $this->results ) {
// Beginning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticket/56841.
$this->request =
"SELECT {$this->query_fields}
{$this->query_from}
{$this->query_where}
{$this->query_orderby}
{$this->query_limit}";
$cache_value = false;
$cache_key = $this->generate_cache_key( $qv, $this->request );
$cache_group = 'user-queries';
if ( $qv['cache_results'] ) {
$cache_value = wp_cache_get( $cache_key, $cache_group );
}
if ( false !== $cache_value ) {
$this->results = $cache_value['user_data'];
$this->total_users = $cache_value['total_users'];
} else {
if ( is_array( $qv['fields'] ) ) {
$this->results = $wpdb->get_results( $this->request );
} else {
$this->results = $wpdb->get_col( $this->request );
}
if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
/**
* Filters SELECT FOUND_ROWS() query for the current WP_User_Query instance.
*
* @since 3.2.0
* @since 5.1.0 Added the `$this` parameter.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query.
* @param WP_User_Query $query The current WP_User_Query instance.
*/
$found_users_query = apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()', $this );
$this->total_users = (int) $wpdb->get_var( $found_users_query );
}
if ( $qv['cache_results'] ) {
$cache_value = array(
'user_data' => $this->results,
'total_users' => $this->total_users,
);
wp_cache_add( $cache_key, $cache_value, $cache_group );
}
}
}
if ( ! $this->results ) {
return;
}
if (
is_array( $qv['fields'] ) &&
isset( $this->results[0]->ID )
) {
foreach ( $this->results as $result ) {
$result->id = $result->ID;
}
} elseif ( 'all_with_meta' === $qv['fields'] || 'all' === $qv['fields'] ) {
if ( function_exists( 'cache_users' ) ) {
cache_users( $this->results );
}
$r = array();
foreach ( $this->results as $userid ) {
if ( 'all_with_meta' === $qv['fields'] ) {
$r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
} else {
$r[] = new WP_User( $userid, '', $qv['blog_id'] );
}
}
$this->results = $r;
}
}
/**
* Retrieves query variable.
*
* @since 3.5.0
*
* @param string $query_var Query variable key.
* @return mixed
*/
public function get( $query_var ) {
if ( isset( $this->query_vars[ $query_var ] ) ) {
return $this->query_vars[ $query_var ];
}
return null;
}
/**
* Sets query variable.
*
* @since 3.5.0
*
* @param string $query_var Query variable key.
* @param mixed $value Query variable value.
*/
public function set( $query_var, $value ) {
$this->query_vars[ $query_var ] = $value;
}
/**
* Used internally to generate an SQL string for searching across multiple columns.
*
* @since 3.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $search Search string.
* @param string[] $columns Array of columns to search.
* @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for single site.
* Single site allows leading and trailing wildcards, Network Admin only trailing.
* @return string
*/
protected function get_search_sql( $search, $columns, $wild = false ) {
global $wpdb;
$searches = array();
$leading_wild = ( 'leading' === $wild || 'both' === $wild ) ? '%' : '';
$trailing_wild = ( 'trailing' === $wild || 'both' === $wild ) ? '%' : '';
$like = $leading_wild . $wpdb->esc_like( $search ) . $trailing_wild;
foreach ( $columns as $column ) {
if ( 'ID' === $column ) {
$searches[] = $wpdb->prepare( "$column = %s", $search );
} else {
$searches[] = $wpdb->prepare( "$column LIKE %s", $like );
}
}
return ' AND (' . implode( ' OR ', $searches ) . ')';
}
/**
* Returns the list of users.
*
* @since 3.1.0
*
* @return array Array of results.
*/
public function get_results() {
return $this->results;
}
/**
* Returns the total number of users for the current query.
*
* @since 3.1.0
*
* @return int Number of total users.
*/
public function get_total() {
return $this->total_users;
}
/**
* Parses and sanitizes 'orderby' keys passed to the user query.
*
* @since 4.2.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $orderby Alias for the field to order by.
* @return string Value to used in the ORDER clause, if `$orderby` is valid.
*/
protected function parse_orderby( $orderby ) {
global $wpdb;
$meta_query_clauses = $this->meta_query->get_clauses();
$_orderby = '';
if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ), true ) ) {
$_orderby = 'user_' . $orderby;
} elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ), true ) ) {
$_orderby = $orderby;
} elseif ( 'name' === $orderby || 'display_name' === $orderby ) {
$_orderby = 'display_name';
} elseif ( 'post_count' === $orderby ) {
// @todo Avoid the JOIN.
$where = get_posts_by_author_sql( 'post' );
$this->query_from .= " LEFT OUTER JOIN (
SELECT post_author, COUNT(*) as post_count
FROM $wpdb->posts
$where
GROUP BY post_author
) p ON ({$wpdb->users}.ID = p.post_author)";
$_orderby = 'post_count';
} elseif ( 'ID' === $orderby || 'id' === $orderby ) {
$_orderby = 'ID';
} elseif ( 'meta_value' === $orderby || $this->get( 'meta_key' ) === $orderby ) {
$_orderby = "$wpdb->usermeta.meta_value";
} elseif ( 'meta_value_num' === $orderby ) {
$_orderby = "$wpdb->usermeta.meta_value+0";
} elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
$include = wp_parse_id_list( $this->query_vars['include'] );
$include_sql = implode( ',', $include );
$_orderby = "FIELD( $wpdb->users.ID, $include_sql )";
} elseif ( 'nicename__in' === $orderby ) {
$sanitized_nicename__in = array_map( 'esc_sql', $this->query_vars['nicename__in'] );
$nicename__in = implode( "','", $sanitized_nicename__in );
$_orderby = "FIELD( user_nicename, '$nicename__in' )";
} elseif ( 'login__in' === $orderby ) {
$sanitized_login__in = array_map( 'esc_sql', $this->query_vars['login__in'] );
$login__in = implode( "','", $sanitized_login__in );
$_orderby = "FIELD( user_login, '$login__in' )";
} elseif ( isset( $meta_query_clauses[ $orderby ] ) ) {
$meta_clause = $meta_query_clauses[ $orderby ];
$_orderby = sprintf( 'CAST(%s.meta_value AS %s)', esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
}
return $_orderby;
}
/**
* Generate cache key.
*
* @since 6.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param array $args Query arguments.
* @param string $sql SQL statement.
* @return string Cache key.
*/
protected function generate_cache_key( array $args, $sql ) {
global $wpdb;
// Replace wpdb placeholder in the SQL statement used by the cache key.
$sql = $wpdb->remove_placeholder_escape( $sql );
$key = md5( $sql );
$last_changed = wp_cache_get_last_changed( 'users' );
if ( empty( $args['orderby'] ) ) {
// Default order is by 'user_login'.
$ordersby = array( 'user_login' => '' );
} elseif ( is_array( $args['orderby'] ) ) {
$ordersby = $args['orderby'];
} else {
// 'orderby' values may be a comma- or space-separated list.
$ordersby = preg_split( '/[,\s]+/', $args['orderby'] );
}
$blog_id = 0;
if ( isset( $args['blog_id'] ) ) {
$blog_id = absint( $args['blog_id'] );
}
if ( $args['has_published_posts'] || in_array( 'post_count', $ordersby, true ) ) {
$switch = $blog_id && get_current_blog_id() !== $blog_id;
if ( $switch ) {
switch_to_blog( $blog_id );
}
$last_changed .= wp_cache_get_last_changed( 'posts' );
if ( $switch ) {
restore_current_blog();
}
}
return "get_users:$key:$last_changed";
}
/**
* Parses an 'order' query variable and casts it to ASC or DESC as necessary.
*
* @since 4.2.0
*
* @param string $order The 'order' query variable.
* @return string The sanitized 'order' query variable.
*/
protected function parse_order( $order ) {
if ( ! is_string( $order ) || empty( $order ) ) {
return 'DESC';
}
if ( 'ASC' === strtoupper( $order ) ) {
return 'ASC';
} else {
return 'DESC';
}
}
/**
* Makes private properties readable for backward compatibility.
*
* @since 4.0.0
* @since 6.4.0 Getting a dynamic property is deprecated.
*
* @param string $name Property to get.
* @return mixed Property.
*/
public function __get( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
return $this->$name;
}
wp_trigger_error(
__METHOD__,
"The property `{$name}` is not declared. Getting a dynamic property is " .
'deprecated since version 6.4.0! Instead, declare the property on the class.',
E_USER_DEPRECATED
);
return null;
}
/**
* Makes private properties settable for backward compatibility.
*
* @since 4.0.0
* @since 6.4.0 Setting a dynamic property is deprecated.
*
* @param string $name Property to check if set.
* @param mixed $value Property value.
*/
public function __set( $name, $value ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
$this->$name = $value;
return;
}
wp_trigger_error(
__METHOD__,
"The property `{$name}` is not declared. Setting a dynamic property is " .
'deprecated since version 6.4.0! Instead, declare the property on the class.',
E_USER_DEPRECATED
);
}
/**
* Makes private properties checkable for backward compatibility.
*
* @since 4.0.0
* @since 6.4.0 Checking a dynamic property is deprecated.
*
* @param string $name Property to check if set.
* @return bool Whether the property is set.
*/
public function __isset( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
return isset( $this->$name );
}
wp_trigger_error(
__METHOD__,
"The property `{$name}` is not declared. Checking `isset()` on a dynamic property " .
'is deprecated since version 6.4.0! Instead, declare the property on the class.',
E_USER_DEPRECATED
);
return false;
}
/**
* Makes private properties un-settable for backward compatibility.
*
* @since 4.0.0
* @since 6.4.0 Unsetting a dynamic property is deprecated.
*
* @param string $name Property to unset.
*/
public function __unset( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
unset( $this->$name );
return;
}
wp_trigger_error(
__METHOD__,
"A property `{$name}` is not declared. Unsetting a dynamic property is " .
'deprecated since version 6.4.0! Instead, declare the property on the class.',
E_USER_DEPRECATED
);
}
/**
* Makes private/protected methods readable for backward compatibility.
*
* @since 4.0.0
*
* @param string $name Method to call.
* @param array $arguments Arguments to pass when calling.
* @return mixed Return value of the callback, false otherwise.
*/
public function __call( $name, $arguments ) {
if ( 'get_search_sql' === $name ) {
return $this->get_search_sql( ...$arguments );
}
return false;
}
}
<?php
/**
* Post API: Walker_PageDropdown class
*
* @package WordPress
* @subpackage Post
* @since 4.4.0
*/
/**
* Core class used to create an HTML drop-down list of pages.
*
* @since 2.1.0
*
* @see Walker
*/
class Walker_PageDropdown extends Walker {
/**
* What the class handles.
*
* @since 2.1.0
* @var string
*
* @see Walker::$tree_type
*/
public $tree_type = 'page';
/**
* Database fields to use.
*
* @since 2.1.0
* @var string[]
*
* @see Walker::$db_fields
* @todo Decouple this
*/
public $db_fields = array(
'parent' => 'post_parent',
'id' => 'ID',
);
/**
* Starts the element output.
*
* @since 2.1.0
* @since 5.9.0 Renamed `$page` to `$data_object` and `$id` to `$current_object_id`
* to match parent class for PHP 8 named parameter support.
*
* @see Walker::start_el()
*
* @param string $output Used to append additional content. Passed by reference.
* @param WP_Post $data_object Page data object.
* @param int $depth Optional. Depth of page in reference to parent pages.
* Used for padding. Default 0.
* @param array $args Optional. Uses 'selected' argument for selected page to
* set selected HTML attribute for option element. Uses
* 'value_field' argument to fill "value" attribute.
* See wp_dropdown_pages(). Default empty array.
* @param int $current_object_id Optional. ID of the current page. Default 0.
*/
public function start_el( &$output, $data_object, $depth = 0, $args = array(), $current_object_id = 0 ) {
// Restores the more descriptive, specific name for use within this method.
$page = $data_object;
$pad = str_repeat( ' ', $depth * 3 );
if ( ! isset( $args['value_field'] ) || ! isset( $page->{$args['value_field']} ) ) {
$args['value_field'] = 'ID';
}
$output .= "\t<option class=\"level-$depth\" value=\"" . esc_attr( $page->{$args['value_field']} ) . '"';
if ( $page->ID === (int) $args['selected'] ) {
$output .= ' selected="selected"';
}
$output .= '>';
$title = $page->post_title;
if ( '' === $title ) {
/* translators: %d: ID of a post. */
$title = sprintf( __( '#%d (no title)' ), $page->ID );
}
/**
* Filters the page title when creating an HTML drop-down list of pages.
*
* @since 3.1.0
*
* @param string $title Page title.
* @param WP_Post $page Page data object.
*/
$title = apply_filters( 'list_pages', $title, $page );
$output .= $pad . esc_html( $title );
$output .= "</option>\n";
}
}
<?php
/**
* Error Protection API: WP_Recovery_Mode_Key_Service class
*
* @package WordPress
* @since 5.2.0
*/
/**
* Core class used to generate and validate keys used to enter Recovery Mode.
*
* @since 5.2.0
*/
#[AllowDynamicProperties]
final class WP_Recovery_Mode_Key_Service {
/**
* The option name used to store the keys.
*
* @since 5.2.0
* @var string
*/
private $option_name = 'recovery_keys';
/**
* Creates a recovery mode token.
*
* @since 5.2.0
*
* @return string A random string to identify its associated key in storage.
*/
public function generate_recovery_mode_token() {
return wp_generate_password( 22, false );
}
/**
* Creates a recovery mode key.
*
* @since 5.2.0
* @since 6.8.0 The stored key is now hashed using wp_fast_hash() instead of phpass.
*
* @param string $token A token generated by {@see generate_recovery_mode_token()}.
* @return string Recovery mode key.
*/
public function generate_and_store_recovery_mode_key( $token ) {
$key = wp_generate_password( 22, false );
$records = $this->get_keys();
$records[ $token ] = array(
'hashed_key' => wp_fast_hash( $key ),
'created_at' => time(),
);
$this->update_keys( $records );
/**
* Fires when a recovery mode key is generated.
*
* @since 5.2.0
*
* @param string $token The recovery data token.
* @param string $key The recovery mode key.
*/
do_action( 'generate_recovery_mode_key', $token, $key );
return $key;
}
/**
* Verifies if the recovery mode key is correct.
*
* Recovery mode keys can only be used once; the key will be consumed in the process.
*
* @since 5.2.0
*
* @param string $token The token used when generating the given key.
* @param string $key The plain text key.
* @param int $ttl Time in seconds for the key to be valid for.
* @return true|WP_Error True on success, error object on failure.
*/
public function validate_recovery_mode_key( $token, $key, $ttl ) {
$records = $this->get_keys();
if ( ! isset( $records[ $token ] ) ) {
return new WP_Error( 'token_not_found', __( 'Recovery Mode not initialized.' ) );
}
$record = $records[ $token ];
$this->remove_key( $token );
if ( ! is_array( $record ) || ! isset( $record['hashed_key'], $record['created_at'] ) ) {
return new WP_Error( 'invalid_recovery_key_format', __( 'Invalid recovery key format.' ) );
}
if ( ! wp_verify_fast_hash( $key, $record['hashed_key'] ) ) {
return new WP_Error( 'hash_mismatch', __( 'Invalid recovery key.' ) );
}
if ( time() > $record['created_at'] + $ttl ) {
return new WP_Error( 'key_expired', __( 'Recovery key expired.' ) );
}
return true;
}
/**
* Removes expired recovery mode keys.
*
* @since 5.2.0
*
* @param int $ttl Time in seconds for the keys to be valid for.
*/
public function clean_expired_keys( $ttl ) {
$records = $this->get_keys();
foreach ( $records as $key => $record ) {
if ( ! isset( $record['created_at'] ) || time() > $record['created_at'] + $ttl ) {
unset( $records[ $key ] );
}
}
$this->update_keys( $records );
}
/**
* Removes a used recovery key.
*
* @since 5.2.0
*
* @param string $token The token used when generating a recovery mode key.
*/
private function remove_key( $token ) {
$records = $this->get_keys();
if ( ! isset( $records[ $token ] ) ) {
return;
}
unset( $records[ $token ] );
$this->update_keys( $records );
}
/**
* Gets the recovery key records.
*
* @since 5.2.0
* @since 6.8.0 Each key is now hashed using wp_fast_hash() instead of phpass.
* Existing keys may still be hashed using phpass.
*
* @return array {
* Associative array of token => data pairs, where the data is an associative
* array of information about the key.
*
* @type array ...$0 {
* Information about the key.
*
* @type string $hashed_key The hashed value of the key.
* @type int $created_at The timestamp when the key was created.
* }
* }
*/
private function get_keys() {
return (array) get_option( $this->option_name, array() );
}
/**
* Updates the recovery key records.
*
* @since 5.2.0
* @since 6.8.0 Each key should now be hashed using wp_fast_hash() instead of phpass.
*
* @param array $keys {
* Associative array of token => data pairs, where the data is an associative
* array of information about the key.
*
* @type array ...$0 {
* Information about the key.
*
* @type string $hashed_key The hashed value of the key.
* @type int $created_at The timestamp when the key was created.
* }
* }
* @return bool True on success, false on failure.
*/
private function update_keys( array $keys ) {
return update_option( $this->option_name, $keys, false );
}
}
<?php
/**
* Session API: WP_User_Meta_Session_Tokens class
*
* @package WordPress
* @subpackage Session
* @since 4.7.0
*/
/**
* Meta-based user sessions token manager.
*
* @since 4.0.0
*
* @see WP_Session_Tokens
*/
class WP_User_Meta_Session_Tokens extends WP_Session_Tokens {
/**
* Retrieves all sessions of the user.
*
* @since 4.0.0
*
* @return array Sessions of the user.
*/
protected function get_sessions() {
$sessions = get_user_meta( $this->user_id, 'session_tokens', true );
if ( ! is_array( $sessions ) ) {
return array();
}
$sessions = array_map( array( $this, 'prepare_session' ), $sessions );
return array_filter( $sessions, array( $this, 'is_still_valid' ) );
}
/**
* Converts an expiration to an array of session information.
*
* @param mixed $session Session or expiration.
* @return array Session.
*/
protected function prepare_session( $session ) {
if ( is_int( $session ) ) {
return array( 'expiration' => $session );
}
return $session;
}
/**
* Retrieves a session based on its verifier (token hash).
*
* @since 4.0.0
*
* @param string $verifier Verifier for the session to retrieve.
* @return array|null The session, or null if it does not exist
*/
protected function get_session( $verifier ) {
$sessions = $this->get_sessions();
if ( isset( $sessions[ $verifier ] ) ) {
return $sessions[ $verifier ];
}
return null;
}
/**
* Updates a session based on its verifier (token hash).
*
* @since 4.0.0
*
* @param string $verifier Verifier for the session to update.
* @param array $session Optional. Session. Omitting this argument destroys the session.
*/
protected function update_session( $verifier, $session = null ) {
$sessions = $this->get_sessions();
if ( $session ) {
$sessions[ $verifier ] = $session;
} else {
unset( $sessions[ $verifier ] );
}
$this->update_sessions( $sessions );
}
/**
* Updates the user's sessions in the usermeta table.
*
* @since 4.0.0
*
* @param array $sessions Sessions.
*/
protected function update_sessions( $sessions ) {
if ( $sessions ) {
update_user_meta( $this->user_id, 'session_tokens', $sessions );
} else {
delete_user_meta( $this->user_id, 'session_tokens' );
}
}
/**
* Destroys all sessions for this user, except the single session with the given verifier.
*
* @since 4.0.0
*
* @param string $verifier Verifier of the session to keep.
*/
protected function destroy_other_sessions( $verifier ) {
$session = $this->get_session( $verifier );
$this->update_sessions( array( $verifier => $session ) );
}
/**
* Destroys all session tokens for the user.
*
* @since 4.0.0
*/
protected function destroy_all_sessions() {
$this->update_sessions( array() );
}
/**
* Destroys all sessions for all users.
*
* @since 4.0.0
*/
public static function drop_sessions() {
delete_metadata( 'user', 0, 'session_tokens', false, true );
}
}
<?php
/**
* These functions are needed to load Multisite.
*
* @since 3.0.0
*
* @package WordPress
* @subpackage Multisite
*/
/**
* Whether a subdomain configuration is enabled.
*
* @since 3.0.0
*
* @return bool True if subdomain configuration is enabled, false otherwise.
*/
function is_subdomain_install() {
if ( defined( 'SUBDOMAIN_INSTALL' ) ) {
return SUBDOMAIN_INSTALL;
}
return ( defined( 'VHOST' ) && 'yes' === VHOST );
}
/**
* Returns array of network plugin files to be included in global scope.
*
* The default directory is wp-content/plugins. To change the default directory
* manually, define `WP_PLUGIN_DIR` and `WP_PLUGIN_URL` in `wp-config.php`.
*
* @access private
* @since 3.1.0
*
* @return string[] Array of absolute paths to files to include.
*/
function wp_get_active_network_plugins() {
$active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
if ( empty( $active_plugins ) ) {
return array();
}
$plugins = array();
$active_plugins = array_keys( $active_plugins );
sort( $active_plugins );
foreach ( $active_plugins as $plugin ) {
if ( ! validate_file( $plugin ) // $plugin must validate as file.
&& str_ends_with( $plugin, '.php' ) // $plugin must end with '.php'.
&& file_exists( WP_PLUGIN_DIR . '/' . $plugin ) // $plugin must exist.
) {
$plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
}
}
return $plugins;
}
/**
* Checks status of current blog.
*
* Checks if the blog is deleted, inactive, archived, or spammed.
*
* Dies with a default message if the blog does not pass the check.
*
* To change the default message when a blog does not pass the check,
* use the wp-content/blog-deleted.php, blog-inactive.php and
* blog-suspended.php drop-ins.
*
* @since 3.0.0
*
* @return true|string Returns true on success, or drop-in file to include.
*/
function ms_site_check() {
/**
* Filters checking the status of the current blog.
*
* @since 3.0.0
*
* @param bool|null $check Whether to skip the blog status check. Default null.
*/
$check = apply_filters( 'ms_site_check', null );
if ( null !== $check ) {
return true;
}
// Allow super admins to see blocked sites.
if ( is_super_admin() ) {
return true;
}
$blog = get_site();
if ( '1' === $blog->deleted ) {
if ( file_exists( WP_CONTENT_DIR . '/blog-deleted.php' ) ) {
return WP_CONTENT_DIR . '/blog-deleted.php';
} else {
wp_die( __( 'This site is no longer available.' ), '', array( 'response' => 410 ) );
}
}
if ( '2' === $blog->deleted ) {
if ( file_exists( WP_CONTENT_DIR . '/blog-inactive.php' ) ) {
return WP_CONTENT_DIR . '/blog-inactive.php';
} else {
$admin_email = str_replace( '@', ' AT ', get_site_option( 'admin_email', 'support@' . get_network()->domain ) );
wp_die(
sprintf(
/* translators: %s: Admin email link. */
__( 'This site has not been activated yet. If you are having problems activating your site, please contact %s.' ),
sprintf( '<a href="mailto:%1$s">%1$s</a>', $admin_email )
)
);
}
}
if ( '1' === $blog->archived || '1' === $blog->spam ) {
if ( file_exists( WP_CONTENT_DIR . '/blog-suspended.php' ) ) {
return WP_CONTENT_DIR . '/blog-suspended.php';
} else {
wp_die( __( 'This site has been archived or suspended.' ), '', array( 'response' => 410 ) );
}
}
return true;
}
/**
* Retrieves the closest matching network for a domain and path.
*
* @since 3.9.0
*
* @internal In 4.4.0, converted to a wrapper for WP_Network::get_by_path()
*
* @param string $domain Domain to check.
* @param string $path Path to check.
* @param int|null $segments Path segments to use. Defaults to null, or the full path.
* @return WP_Network|false Network object if successful. False when no network is found.
*/
function get_network_by_path( $domain, $path, $segments = null ) {
return WP_Network::get_by_path( $domain, $path, $segments );
}
/**
* Retrieves the closest matching site object by its domain and path.
*
* This will not necessarily return an exact match for a domain and path. Instead, it
* breaks the domain and path into pieces that are then used to match the closest
* possibility from a query.
*
* The intent of this method is to match a site object during bootstrap for a
* requested site address
*
* @since 3.9.0
* @since 4.7.0 Updated to always return a `WP_Site` object.
*
* @param string $domain Domain to check.
* @param string $path Path to check.
* @param int|null $segments Path segments to use. Defaults to null, or the full path.
* @return WP_Site|false Site object if successful. False when no site is found.
*/
function get_site_by_path( $domain, $path, $segments = null ) {
$path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
/**
* Filters the number of path segments to consider when searching for a site.
*
* @since 3.9.0
*
* @param int|null $segments The number of path segments to consider. WordPress by default looks at
* one path segment following the network path. The function default of
* null only makes sense when you know the requested path should match a site.
* @param string $domain The requested domain.
* @param string $path The requested path, in full.
*/
$segments = apply_filters( 'site_by_path_segments_count', $segments, $domain, $path );
if ( null !== $segments && count( $path_segments ) > $segments ) {
$path_segments = array_slice( $path_segments, 0, $segments );
}
$paths = array();
while ( count( $path_segments ) ) {
$paths[] = '/' . implode( '/', $path_segments ) . '/';
array_pop( $path_segments );
}
$paths[] = '/';
/**
* Determines a site by its domain and path.
*
* This allows one to short-circuit the default logic, perhaps by
* replacing it with a routine that is more optimal for your setup.
*
* Return null to avoid the short-circuit. Return false if no site
* can be found at the requested domain and path. Otherwise, return
* a site object.
*
* @since 3.9.0
*
* @param null|false|WP_Site $site Site value to return by path. Default null
* to continue retrieving the site.
* @param string $domain The requested domain.
* @param string $path The requested path, in full.
* @param int|null $segments The suggested number of paths to consult.
* Default null, meaning the entire path was to be consulted.
* @param string[] $paths The paths to search for, based on $path and $segments.
*/
$pre = apply_filters( 'pre_get_site_by_path', null, $domain, $path, $segments, $paths );
if ( null !== $pre ) {
if ( false !== $pre && ! $pre instanceof WP_Site ) {
$pre = new WP_Site( $pre );
}
return $pre;
}
/*
* @todo
* Caching, etc. Consider alternative optimization routes,
* perhaps as an opt-in for plugins, rather than using the pre_* filter.
* For example: The segments filter can expand or ignore paths.
* If persistent caching is enabled, we could query the DB for a path <> '/'
* then cache whether we can just always ignore paths.
*/
/*
* Either www or non-www is supported, not both. If a www domain is requested,
* query for both to provide the proper redirect.
*/
$domains = array( $domain );
if ( str_starts_with( $domain, 'www.' ) ) {
$domains[] = substr( $domain, 4 );
}
$args = array(
'number' => 1,
'update_site_meta_cache' => false,
);
if ( count( $domains ) > 1 ) {
$args['domain__in'] = $domains;
$args['orderby']['domain_length'] = 'DESC';
} else {
$args['domain'] = array_shift( $domains );
}
if ( count( $paths ) > 1 ) {
$args['path__in'] = $paths;
$args['orderby']['path_length'] = 'DESC';
} else {
$args['path'] = array_shift( $paths );
}
$result = get_sites( $args );
$site = array_shift( $result );
if ( $site ) {
return $site;
}
return false;
}
/**
* Identifies the network and site of a requested domain and path and populates the
* corresponding network and site global objects as part of the multisite bootstrap process.
*
* Prior to 4.6.0, this was a procedural block in `ms-settings.php`. It was wrapped into
* a function to facilitate unit tests. It should not be used outside of core.
*
* Usually, it's easier to query the site first, which then declares its network.
* In limited situations, we either can or must find the network first.
*
* If a network and site are found, a `true` response will be returned so that the
* request can continue.
*
* If neither a network or site is found, `false` or a URL string will be returned
* so that either an error can be shown or a redirect can occur.
*
* @since 4.6.0
* @access private
*
* @global WP_Network $current_site The current network.
* @global WP_Site $current_blog The current site.
*
* @param string $domain The requested domain.
* @param string $path The requested path.
* @param bool $subdomain Optional. Whether a subdomain (true) or subdirectory (false) configuration.
* Default false.
* @return bool|string True if bootstrap successfully populated `$current_blog` and `$current_site`.
* False if bootstrap could not be properly completed.
* Redirect URL if parts exist, but the request as a whole can not be fulfilled.
*/
function ms_load_current_site_and_network( $domain, $path, $subdomain = false ) {
global $current_site, $current_blog;
// If the network is defined in wp-config.php, we can simply use that.
if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) {
$current_site = new stdClass();
$current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1;
$current_site->domain = DOMAIN_CURRENT_SITE;
$current_site->path = PATH_CURRENT_SITE;
if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
$current_site->blog_id = BLOG_ID_CURRENT_SITE;
} elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) { // Deprecated.
$current_site->blog_id = BLOGID_CURRENT_SITE;
}
if ( 0 === strcasecmp( $current_site->domain, $domain ) && 0 === strcasecmp( $current_site->path, $path ) ) {
$current_blog = get_site_by_path( $domain, $path );
} elseif ( '/' !== $current_site->path && 0 === strcasecmp( $current_site->domain, $domain ) && 0 === stripos( $path, $current_site->path ) ) {
/*
* If the current network has a path and also matches the domain and path of the request,
* we need to look for a site using the first path segment following the network's path.
*/
$current_blog = get_site_by_path( $domain, $path, 1 + count( explode( '/', trim( $current_site->path, '/' ) ) ) );
} else {
// Otherwise, use the first path segment (as usual).
$current_blog = get_site_by_path( $domain, $path, 1 );
}
} elseif ( ! $subdomain ) {
/*
* A "subdomain" installation can be re-interpreted to mean "can support any domain".
* If we're not dealing with one of these installations, then the important part is determining
* the network first, because we need the network's path to identify any sites.
*/
$current_site = wp_cache_get( 'current_network', 'site-options' );
if ( ! $current_site ) {
// Are there even two networks installed?
$networks = get_networks( array( 'number' => 2 ) );
if ( count( $networks ) === 1 ) {
$current_site = array_shift( $networks );
wp_cache_add( 'current_network', $current_site, 'site-options' );
} elseif ( empty( $networks ) ) {
// A network not found hook should fire here.
return false;
}
}
if ( empty( $current_site ) ) {
$current_site = WP_Network::get_by_path( $domain, $path, 1 );
}
if ( empty( $current_site ) ) {
/**
* Fires when a network cannot be found based on the requested domain and path.
*
* At the time of this action, the only recourse is to redirect somewhere
* and exit. If you want to declare a particular network, do so earlier.
*
* @since 4.4.0
*
* @param string $domain The domain used to search for a network.
* @param string $path The path used to search for a path.
*/
do_action( 'ms_network_not_found', $domain, $path );
return false;
} elseif ( $path === $current_site->path ) {
$current_blog = get_site_by_path( $domain, $path );
} else {
// Search the network path + one more path segment (on top of the network path).
$current_blog = get_site_by_path( $domain, $path, substr_count( $current_site->path, '/' ) );
}
} else {
// Find the site by the domain and at most the first path segment.
$current_blog = get_site_by_path( $domain, $path, 1 );
if ( $current_blog ) {
$current_site = WP_Network::get_instance( $current_blog->site_id ? $current_blog->site_id : 1 );
} else {
// If you don't have a site with the same domain/path as a network, you're pretty screwed, but:
$current_site = WP_Network::get_by_path( $domain, $path, 1 );
}
}
// The network declared by the site trumps any constants.
if ( $current_blog && (int) $current_blog->site_id !== $current_site->id ) {
$current_site = WP_Network::get_instance( $current_blog->site_id );
}
// No network has been found, bail.
if ( empty( $current_site ) ) {
/** This action is documented in wp-includes/ms-settings.php */
do_action( 'ms_network_not_found', $domain, $path );
return false;
}
// During activation of a new subdomain, the requested site does not yet exist.
if ( empty( $current_blog ) && wp_installing() ) {
$current_blog = new stdClass();
$current_blog->blog_id = 1;
$blog_id = 1;
$current_blog->public = 1;
}
// No site has been found, bail.
if ( empty( $current_blog ) ) {
// We're going to redirect to the network URL, with some possible modifications.
$scheme = is_ssl() ? 'https' : 'http';
$destination = "$scheme://{$current_site->domain}{$current_site->path}";
/**
* Fires when a network can be determined but a site cannot.
*
* At the time of this action, the only recourse is to redirect somewhere
* and exit. If you want to declare a particular site, do so earlier.
*
* @since 3.9.0
*
* @param WP_Network $current_site The network that had been determined.
* @param string $domain The domain used to search for a site.
* @param string $path The path used to search for a site.
*/
do_action( 'ms_site_not_found', $current_site, $domain, $path );
if ( $subdomain && ! defined( 'NOBLOGREDIRECT' ) ) {
// For a "subdomain" installation, redirect to the signup form specifically.
$destination .= 'wp-signup.php?new=' . str_replace( '.' . $current_site->domain, '', $domain );
} elseif ( $subdomain ) {
/*
* For a "subdomain" installation, the NOBLOGREDIRECT constant
* can be used to avoid a redirect to the signup form.
* Using the ms_site_not_found action is preferred to the constant.
*/
if ( '%siteurl%' !== NOBLOGREDIRECT ) {
$destination = NOBLOGREDIRECT;
}
} elseif ( 0 === strcasecmp( $current_site->domain, $domain ) ) {
/*
* If the domain we were searching for matches the network's domain,
* it's no use redirecting back to ourselves -- it'll cause a loop.
* As we couldn't find a site, we're simply not installed.
*/
return false;
}
return $destination;
}
// Figure out the current network's main site.
if ( empty( $current_site->blog_id ) ) {
$current_site->blog_id = get_main_site_id( $current_site->id );
}
return true;
}
/**
* Displays a failure message.
*
* Used when a blog's tables do not exist. Checks for a missing $wpdb->site table as well.
*
* @access private
* @since 3.0.0
* @since 4.4.0 The `$domain` and `$path` parameters were added.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $domain The requested domain for the error to reference.
* @param string $path The requested path for the error to reference.
*/
function ms_not_installed( $domain, $path ) {
global $wpdb;
if ( ! is_admin() ) {
dead_db();
}
wp_load_translations_early();
$title = __( 'Error establishing a database connection' );
$msg = '<h1>' . $title . '</h1>';
$msg .= '<p>' . __( 'If your site does not display, please contact the owner of this network.' ) . '';
$msg .= ' ' . __( 'If you are the owner of this network please check that your host’s database server is running properly and all tables are error free.' ) . '</p>';
$query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $wpdb->site ) );
if ( ! $wpdb->get_var( $query ) ) {
$msg .= '<p>' . sprintf(
/* translators: %s: Table name. */
__( '<strong>Database tables are missing.</strong> This means that your host’s database server is not running, WordPress was not installed properly, or someone deleted %s. You really should look at your database now.' ),
'<code>' . $wpdb->site . '</code>'
) . '</p>';
} else {
$msg .= '<p>' . sprintf(
/* translators: 1: Site URL, 2: Table name, 3: Database name. */
__( '<strong>Could not find site %1$s.</strong> Searched for table %2$s in database %3$s. Is that right?' ),
'<code>' . rtrim( $domain . $path, '/' ) . '</code>',
'<code>' . $wpdb->blogs . '</code>',
'<code>' . DB_NAME . '</code>'
) . '</p>';
}
$msg .= '<p><strong>' . __( 'What do I do now?' ) . '</strong> ';
$msg .= sprintf(
/* translators: %s: Documentation URL. */
__( 'Read the <a href="%s" target="_blank">Debugging a WordPress Network</a> article. Some of the suggestions there may help you figure out what went wrong.' ),
__( 'https://developer.wordpress.org/advanced-administration/debug/debug-network/' )
);
$msg .= ' ' . __( 'If you are still stuck with this message, then check that your database contains the following tables:' ) . '</p><ul>';
foreach ( $wpdb->tables( 'global' ) as $t => $table ) {
if ( 'sitecategories' === $t ) {
continue;
}
$msg .= '<li>' . $table . '</li>';
}
$msg .= '</ul>';
wp_die( $msg, $title, array( 'response' => 500 ) );
}
/**
* This deprecated function formerly set the site_name property of the $current_site object.
*
* This function simply returns the object, as before.
* The bootstrap takes care of setting site_name.
*
* @access private
* @since 3.0.0
* @deprecated 3.9.0 Use get_current_site() instead.
*
* @param WP_Network $current_site
* @return WP_Network
*/
function get_current_site_name( $current_site ) {
_deprecated_function( __FUNCTION__, '3.9.0', 'get_current_site()' );
return $current_site;
}
/**
* This deprecated function managed much of the site and network loading in multisite.
*
* The current bootstrap code is now responsible for parsing the site and network load as
* well as setting the global $current_site object.
*
* @access private
* @since 3.0.0
* @deprecated 3.9.0
*
* @global WP_Network $current_site
*
* @return WP_Network
*/
function wpmu_current_site() {
global $current_site;
_deprecated_function( __FUNCTION__, '3.9.0' );
return $current_site;
}
/**
* Retrieves an object containing information about the requested network.
*
* @since 3.9.0
* @deprecated 4.7.0 Use get_network()
* @see get_network()
*
* @internal In 4.6.0, converted to use get_network()
*
* @param object|int $network The network's database row or ID.
* @return WP_Network|false Object containing network information if found, false if not.
*/
function wp_get_network( $network ) {
_deprecated_function( __FUNCTION__, '4.7.0', 'get_network()' );
$network = get_network( $network );
if ( null === $network ) {
return false;
}
return $network;
}
<?php
/**
* Atom Feed Template for displaying Atom Posts feed.
*
* @package WordPress
*/
// Don't load directly.
if ( ! defined( 'ABSPATH' ) ) {
die( '-1' );
}
header( 'Content-Type: ' . feed_content_type( 'atom' ) . '; charset=' . get_option( 'blog_charset' ), true );
$more = 1;
echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>';
/** This action is documented in wp-includes/feed-rss2.php */
do_action( 'rss_tag_pre', 'atom' );
?>
<feed
xmlns="http://www.w3.org/2005/Atom"
xmlns:thr="http://purl.org/syndication/thread/1.0"
xml:lang="<?php bloginfo_rss( 'language' ); ?>"
<?php
/**
* Fires at end of the Atom feed root to add namespaces.
*
* @since 2.0.0
*/
do_action( 'atom_ns' );
?>
>
<title type="text"><?php wp_title_rss(); ?></title>
<subtitle type="text"><?php bloginfo_rss( 'description' ); ?></subtitle>
<updated><?php echo get_feed_build_date( 'Y-m-d\TH:i:s\Z' ); ?></updated>
<link rel="alternate" type="<?php bloginfo_rss( 'html_type' ); ?>" href="<?php bloginfo_rss( 'url' ); ?>" />
<id><?php bloginfo( 'atom_url' ); ?></id>
<link rel="self" type="application/atom+xml" href="<?php self_link(); ?>" />
<?php
/**
* Fires just before the first Atom feed entry.
*
* @since 2.0.0
*/
do_action( 'atom_head' );
while ( have_posts() ) :
the_post();
?>
<entry>
<author>
<name><?php the_author(); ?></name>
<?php
$author_url = get_the_author_meta( 'url' );
if ( ! empty( $author_url ) ) :
?>
<uri><?php the_author_meta( 'url' ); ?></uri>
<?php
endif;
/**
* Fires at the end of each Atom feed author entry.
*
* @since 3.2.0
*/
do_action( 'atom_author' );
?>
</author>
<title type="<?php html_type_rss(); ?>"><![CDATA[<?php the_title_rss(); ?>]]></title>
<link rel="alternate" type="<?php bloginfo_rss( 'html_type' ); ?>" href="<?php the_permalink_rss(); ?>" />
<id><?php the_guid(); ?></id>
<updated><?php echo get_post_modified_time( 'Y-m-d\TH:i:s\Z', true ); ?></updated>
<published><?php echo get_post_time( 'Y-m-d\TH:i:s\Z', true ); ?></published>
<?php the_category_rss( 'atom' ); ?>
<summary type="<?php html_type_rss(); ?>"><![CDATA[<?php the_excerpt_rss(); ?>]]></summary>
<?php if ( ! get_option( 'rss_use_excerpt' ) ) : ?>
<content type="<?php html_type_rss(); ?>" xml:base="<?php the_permalink_rss(); ?>"><![CDATA[<?php the_content_feed( 'atom' ); ?>]]></content>
<?php endif; ?>
<?php
atom_enclosure();
/**
* Fires at the end of each Atom feed item.
*
* @since 2.0.0
*/
do_action( 'atom_entry' );
if ( get_comments_number() || comments_open() ) :
?>
<link rel="replies" type="<?php bloginfo_rss( 'html_type' ); ?>" href="<?php the_permalink_rss(); ?>#comments" thr:count="<?php echo get_comments_number(); ?>" />
<link rel="replies" type="application/atom+xml" href="<?php echo esc_url( get_post_comments_feed_link( 0, 'atom' ) ); ?>" thr:count="<?php echo get_comments_number(); ?>" />
<thr:total><?php echo get_comments_number(); ?></thr:total>
<?php endif; ?>
</entry>
<?php endwhile; ?>
</feed>
<?php
/**
* Block Metadata Registry
*
* @package WordPress
* @subpackage Blocks
* @since 6.7.0
*/
/**
* Class used for managing block metadata collections.
*
* The WP_Block_Metadata_Registry allows plugins to register metadata for large
* collections of blocks (e.g., 50-100+) using a single PHP file. This approach
* reduces the need to read and decode multiple `block.json` files, enhancing
* performance through opcode caching.
*
* @since 6.7.0
*/
class WP_Block_Metadata_Registry {
/**
* Container for storing block metadata collections.
*
* Each entry maps a base path to its corresponding metadata and callback.
*
* @since 6.7.0
* @var array<string, array<string, mixed>>
*/
private static $collections = array();
/**
* Caches the last matched collection path for performance optimization.
*
* @since 6.7.0
* @var string|null
*/
private static $last_matched_collection = null;
/**
* Stores the default allowed collection root paths.
*
* @since 6.7.2
* @var string[]|null
*/
private static $default_collection_roots = null;
/**
* Registers a block metadata collection.
*
* This method allows registering a collection of block metadata from a single
* manifest file, improving performance for large sets of blocks.
*
* The manifest file should be a PHP file that returns an associative array, where
* the keys are the block identifiers (without their namespace) and the values are
* the corresponding block metadata arrays. The block identifiers must match the
* parent directory name for the respective `block.json` file.
*
* Example manifest file structure:
* ```
* return array(
* 'example-block' => array(
* 'title' => 'Example Block',
* 'category' => 'widgets',
* 'icon' => 'smiley',
* // ... other block metadata
* ),
* 'another-block' => array(
* 'title' => 'Another Block',
* 'category' => 'formatting',
* 'icon' => 'star-filled',
* // ... other block metadata
* ),
* // ... more block metadata entries
* );
* ```
*
* @since 6.7.0
*
* @param string $path The absolute base path for the collection ( e.g., WP_PLUGIN_DIR . '/my-plugin/blocks/' ).
* @param string $manifest The absolute path to the manifest file containing the metadata collection.
* @return bool True if the collection was registered successfully, false otherwise.
*/
public static function register_collection( $path, $manifest ) {
$path = rtrim( wp_normalize_path( $path ), '/' );
$collection_roots = self::get_default_collection_roots();
/**
* Filters the root directory paths for block metadata collections.
*
* Any block metadata collection that is registered must not use any of these paths, or any parent directory
* path of them. Most commonly, block metadata collections should reside within one of these paths, though in
* some scenarios they may also reside in entirely different directories (e.g. in case of symlinked plugins).
*
* Example:
* * It is allowed to register a collection with path `WP_PLUGIN_DIR . '/my-plugin'`.
* * It is not allowed to register a collection with path `WP_PLUGIN_DIR`.
* * It is not allowed to register a collection with path `dirname( WP_PLUGIN_DIR )`.
*
* The default list encompasses the `wp-includes` directory, as well as the root directories for plugins,
* must-use plugins, and themes. This filter can be used to expand the list, e.g. to custom directories that
* contain symlinked plugins, so that these root directories cannot be used themselves for a block metadata
* collection either.
*
* @since 6.7.2
*
* @param string[] $collection_roots List of allowed metadata collection root paths.
*/
$collection_roots = apply_filters( 'wp_allowed_block_metadata_collection_roots', $collection_roots );
$collection_roots = array_unique(
array_map(
static function ( $allowed_root ) {
return rtrim( wp_normalize_path( $allowed_root ), '/' );
},
$collection_roots
)
);
// Check if the path is valid:
if ( ! self::is_valid_collection_path( $path, $collection_roots ) ) {
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: %s: list of allowed collection roots */
__( 'Block metadata collections cannot be registered as one of the following directories or their parent directories: %s' ),
esc_html( implode( wp_get_list_item_separator(), $collection_roots ) )
),
'6.7.2'
);
return false;
}
if ( ! file_exists( $manifest ) ) {
_doing_it_wrong(
__METHOD__,
__( 'The specified manifest file does not exist.' ),
'6.7.0'
);
return false;
}
self::$collections[ $path ] = array(
'manifest' => $manifest,
'metadata' => null,
);
return true;
}
/**
* Retrieves block metadata for a given block within a specific collection.
*
* This method uses the registered collections to efficiently lookup
* block metadata without reading individual `block.json` files.
*
* @since 6.7.0
*
* @param string $file_or_folder The path to the file or folder containing the block.
* @return array|null The block metadata for the block, or null if not found.
*/
public static function get_metadata( $file_or_folder ) {
$file_or_folder = wp_normalize_path( $file_or_folder );
$path = self::find_collection_path( $file_or_folder );
if ( ! $path ) {
return null;
}
$collection = &self::$collections[ $path ];
if ( null === $collection['metadata'] ) {
// Load the manifest file if not already loaded
$collection['metadata'] = require $collection['manifest'];
}
// Get the block name from the path.
$block_name = self::default_identifier_callback( $file_or_folder );
return isset( $collection['metadata'][ $block_name ] ) ? $collection['metadata'][ $block_name ] : null;
}
/**
* Gets the list of absolute paths to all block metadata files that are part of the given collection.
*
* For instance, if a block metadata collection is registered with path `WP_PLUGIN_DIR . '/my-plugin/blocks/'`,
* and the manifest file includes metadata for two blocks `'block-a'` and `'block-b'`, the result of this method
* will be an array containing:
* * `WP_PLUGIN_DIR . '/my-plugin/blocks/block-a/block.json'`
* * `WP_PLUGIN_DIR . '/my-plugin/blocks/block-b/block.json'`
*
* @since 6.8.0
*
* @param string $path The absolute base path for a previously registered collection.
* @return string[] List of block metadata file paths, or an empty array if the given `$path` is invalid.
*/
public static function get_collection_block_metadata_files( $path ) {
$path = rtrim( wp_normalize_path( $path ), '/' );
if ( ! isset( self::$collections[ $path ] ) ) {
_doing_it_wrong(
__METHOD__,
__( 'No registered block metadata collection was found for the provided path.' ),
'6.8.0'
);
return array();
}
$collection = &self::$collections[ $path ];
if ( null === $collection['metadata'] ) {
// Load the manifest file if not already loaded.
$collection['metadata'] = require $collection['manifest'];
}
return array_map(
// No normalization necessary since `$path` is already normalized and `$block_name` is just a folder name.
static function ( $block_name ) use ( $path ) {
return "{$path}/{$block_name}/block.json";
},
array_keys( $collection['metadata'] )
);
}
/**
* Finds the collection path for a given file or folder.
*
* @since 6.7.0
*
* @param string $file_or_folder The normalized path to the file or folder.
* @return string|null The normalized collection path if found, or null if not found.
*/
private static function find_collection_path( $file_or_folder ) {
if ( empty( $file_or_folder ) ) {
return null;
}
// Check the last matched collection first, since block registration usually happens in batches per plugin or theme.
$path = rtrim( $file_or_folder, '/' );
if ( self::$last_matched_collection && str_starts_with( $path, self::$last_matched_collection ) ) {
return self::$last_matched_collection;
}
$collection_paths = array_keys( self::$collections );
foreach ( $collection_paths as $collection_path ) {
if ( str_starts_with( $path, $collection_path ) ) {
self::$last_matched_collection = $collection_path;
return $collection_path;
}
}
return null;
}
/**
* Checks if metadata exists for a given block name in a specific collection.
*
* @since 6.7.0
*
* @param string $file_or_folder The path to the file or folder containing the block metadata.
* @return bool True if metadata exists for the block, false otherwise.
*/
public static function has_metadata( $file_or_folder ) {
return null !== self::get_metadata( $file_or_folder );
}
/**
* Default identifier function to determine the block identifier from a given path.
*
* This function extracts the block identifier from the path:
* - For 'block.json' files, it uses the parent directory name.
* - For directories, it uses the directory name itself.
* - For empty paths, it returns an empty string.
*
* For example:
* - Path: '/wp-content/plugins/my-plugin/blocks/example/block.json'
* Identifier: 'example'
* - Path: '/wp-content/plugins/my-plugin/blocks/another-block'
* Identifier: 'another-block'
*
* This default behavior matches the standard WordPress block structure.
*
* @since 6.7.0
*
* @param string $path The normalized file or folder path to determine the block identifier from.
* @return string The block identifier, or an empty string if the path is empty.
*/
private static function default_identifier_callback( $path ) {
// Ensure $path is not empty to prevent unexpected behavior.
if ( empty( $path ) ) {
return '';
}
if ( str_ends_with( $path, 'block.json' ) ) {
// Return the parent directory name if it's a block.json file.
return basename( dirname( $path ) );
}
// Otherwise, assume it's a directory and return its name.
return basename( $path );
}
/**
* Checks whether the given block metadata collection path is valid against the list of collection roots.
*
* @since 6.7.2
*
* @param string $path Normalized block metadata collection path, without trailing slash.
* @param string[] $collection_roots List of normalized collection root paths, without trailing slashes.
* @return bool True if the path is allowed, false otherwise.
*/
private static function is_valid_collection_path( $path, $collection_roots ) {
foreach ( $collection_roots as $allowed_root ) {
// If the path matches any root exactly, it is invalid.
if ( $allowed_root === $path ) {
return false;
}
// If the path is a parent path of any of the roots, it is invalid.
if ( str_starts_with( $allowed_root, $path ) ) {
return false;
}
}
return true;
}
/**
* Gets the default collection root directory paths.
*
* @since 6.7.2
*
* @return string[] List of directory paths within which metadata collections are allowed.
*/
private static function get_default_collection_roots() {
if ( isset( self::$default_collection_roots ) ) {
return self::$default_collection_roots;
}
$collection_roots = array(
wp_normalize_path( ABSPATH . WPINC ),
wp_normalize_path( WP_CONTENT_DIR ),
wp_normalize_path( WPMU_PLUGIN_DIR ),
wp_normalize_path( WP_PLUGIN_DIR ),
);
$theme_roots = get_theme_roots();
if ( ! is_array( $theme_roots ) ) {
$theme_roots = array( $theme_roots );
}
foreach ( $theme_roots as $theme_root ) {
$collection_roots[] = trailingslashit( wp_normalize_path( WP_CONTENT_DIR ) ) . ltrim( wp_normalize_path( $theme_root ), '/' );
}
self::$default_collection_roots = array_unique( $collection_roots );
return self::$default_collection_roots;
}
}
<?php
/**
* API for fetching the HTML to embed remote content based on a provided URL.
*
* This file is deprecated, use 'wp-includes/class-wp-oembed.php' instead.
*
* @deprecated 5.3.0
* @package WordPress
* @subpackage oEmbed
*/
_deprecated_file( basename( __FILE__ ), '5.3.0', WPINC . '/class-wp-oembed.php' );
/** WP_oEmbed class */
require_once ABSPATH . WPINC . '/class-wp-oembed.php';
<?php
/**
* Network API: WP_Network class
*
* @package WordPress
* @subpackage Multisite
* @since 4.4.0
*/
/**
* Core class used for interacting with a multisite network.
*
* This class is used during load to populate the `$current_site` global and
* setup the current network.
*
* This class is most useful in WordPress multi-network installations where the
* ability to interact with any network of sites is required.
*
* @since 4.4.0
*
* @property int $id
* @property int $site_id
*/
#[AllowDynamicProperties]
class WP_Network {
/**
* Network ID.
*
* @since 4.4.0
* @since 4.6.0 Converted from public to private to explicitly enable more intuitive
* access via magic methods. As part of the access change, the type was
* also changed from `string` to `int`.
* @var int
*/
private $id;
/**
* Domain of the network.
*
* @since 4.4.0
* @var string
*/
public $domain = '';
/**
* Path of the network.
*
* @since 4.4.0
* @var string
*/
public $path = '';
/**
* The ID of the network's main site.
*
* Named "blog" vs. "site" for legacy reasons. A main site is mapped to
* the network when the network is created.
*
* A numeric string, for compatibility reasons.
*
* @since 4.4.0
* @var string
*/
private $blog_id = '0';
/**
* Domain used to set cookies for this network.
*
* @since 4.4.0
* @var string
*/
public $cookie_domain = '';
/**
* Name of this network.
*
* Named "site" vs. "network" for legacy reasons.
*
* @since 4.4.0
* @var string
*/
public $site_name = '';
/**
* Retrieves a network from the database by its ID.
*
* @since 4.4.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $network_id The ID of the network to retrieve.
* @return WP_Network|false The network's object if found. False if not.
*/
public static function get_instance( $network_id ) {
global $wpdb;
$network_id = (int) $network_id;
if ( ! $network_id ) {
return false;
}
$_network = wp_cache_get( $network_id, 'networks' );
if ( false === $_network ) {
$_network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) );
if ( empty( $_network ) || is_wp_error( $_network ) ) {
$_network = -1;
}
wp_cache_add( $network_id, $_network, 'networks' );
}
if ( is_numeric( $_network ) ) {
return false;
}
return new WP_Network( $_network );
}
/**
* Creates a new WP_Network object.
*
* Will populate object properties from the object provided and assign other
* default properties based on that information.
*
* @since 4.4.0
*
* @param WP_Network|object $network A network object.
*/
public function __construct( $network ) {
foreach ( get_object_vars( $network ) as $key => $value ) {
$this->__set( $key, $value );
}
$this->_set_site_name();
$this->_set_cookie_domain();
}
/**
* Getter.
*
* Allows current multisite naming conventions when getting properties.
*
* @since 4.6.0
*
* @param string $key Property to get.
* @return mixed Value of the property. Null if not available.
*/
public function __get( $key ) {
switch ( $key ) {
case 'id':
return (int) $this->id;
case 'blog_id':
return (string) $this->get_main_site_id();
case 'site_id':
return $this->get_main_site_id();
}
return null;
}
/**
* Isset-er.
*
* Allows current multisite naming conventions when checking for properties.
*
* @since 4.6.0
*
* @param string $key Property to check if set.
* @return bool Whether the property is set.
*/
public function __isset( $key ) {
switch ( $key ) {
case 'id':
case 'blog_id':
case 'site_id':
return true;
}
return false;
}
/**
* Setter.
*
* Allows current multisite naming conventions while setting properties.
*
* @since 4.6.0
*
* @param string $key Property to set.
* @param mixed $value Value to assign to the property.
*/
public function __set( $key, $value ) {
switch ( $key ) {
case 'id':
$this->id = (int) $value;
break;
case 'blog_id':
case 'site_id':
$this->blog_id = (string) $value;
break;
default:
$this->$key = $value;
}
}
/**
* Returns the main site ID for the network.
*
* Internal method used by the magic getter for the 'blog_id' and 'site_id'
* properties.
*
* @since 4.9.0
*
* @return int The ID of the main site.
*/
private function get_main_site_id() {
/**
* Filters the main site ID.
*
* Returning a positive integer will effectively short-circuit the function.
*
* @since 4.9.0
*
* @param int|null $main_site_id If a positive integer is returned, it is interpreted as the main site ID.
* @param WP_Network $network The network object for which the main site was detected.
*/
$main_site_id = (int) apply_filters( 'pre_get_main_site_id', null, $this );
if ( 0 < $main_site_id ) {
return $main_site_id;
}
if ( 0 < (int) $this->blog_id ) {
return (int) $this->blog_id;
}
if ( ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' )
&& DOMAIN_CURRENT_SITE === $this->domain && PATH_CURRENT_SITE === $this->path )
|| ( defined( 'SITE_ID_CURRENT_SITE' ) && (int) SITE_ID_CURRENT_SITE === $this->id )
) {
if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
$this->blog_id = (string) BLOG_ID_CURRENT_SITE;
return (int) $this->blog_id;
}
if ( defined( 'BLOGID_CURRENT_SITE' ) ) { // Deprecated.
$this->blog_id = (string) BLOGID_CURRENT_SITE;
return (int) $this->blog_id;
}
}
$site = get_site();
if ( $site->domain === $this->domain && $site->path === $this->path ) {
$main_site_id = (int) $site->id;
} else {
$main_site_id = get_network_option( $this->id, 'main_site' );
if ( false === $main_site_id ) {
$_sites = get_sites(
array(
'fields' => 'ids',
'number' => 1,
'domain' => $this->domain,
'path' => $this->path,
'network_id' => $this->id,
)
);
$main_site_id = ! empty( $_sites ) ? array_shift( $_sites ) : 0;
update_network_option( $this->id, 'main_site', $main_site_id );
}
}
$this->blog_id = (string) $main_site_id;
return (int) $this->blog_id;
}
/**
* Sets the site name assigned to the network if one has not been populated.
*
* @since 4.4.0
*/
private function _set_site_name() {
if ( ! empty( $this->site_name ) ) {
return;
}
$default = ucfirst( $this->domain );
$this->site_name = get_network_option( $this->id, 'site_name', $default );
}
/**
* Sets the cookie domain based on the network domain if one has
* not been populated.
*
* @todo What if the domain of the network doesn't match the current site?
*
* @since 4.4.0
*/
private function _set_cookie_domain() {
if ( ! empty( $this->cookie_domain ) ) {
return;
}
$domain = parse_url( $this->domain, PHP_URL_HOST );
$this->cookie_domain = is_string( $domain ) ? $domain : $this->domain;
if ( str_starts_with( $this->cookie_domain, 'www.' ) ) {
$this->cookie_domain = substr( $this->cookie_domain, 4 );
}
}
/**
* Retrieves the closest matching network for a domain and path.
*
* This will not necessarily return an exact match for a domain and path. Instead, it
* breaks the domain and path into pieces that are then used to match the closest
* possibility from a query.
*
* The intent of this method is to match a network during bootstrap for a
* requested site address.
*
* @since 4.4.0
*
* @param string $domain Domain to check.
* @param string $path Path to check.
* @param int|null $segments Path segments to use. Defaults to null, or the full path.
* @return WP_Network|false Network object if successful. False when no network is found.
*/
public static function get_by_path( $domain = '', $path = '', $segments = null ) {
$domains = array( $domain );
$pieces = explode( '.', $domain );
/*
* It's possible one domain to search is 'com', but it might as well
* be 'localhost' or some other locally mapped domain.
*/
while ( array_shift( $pieces ) ) {
if ( ! empty( $pieces ) ) {
$domains[] = implode( '.', $pieces );
}
}
/*
* If we've gotten to this function during normal execution, there is
* more than one network installed. At this point, who knows how many
* we have. Attempt to optimize for the situation where networks are
* only domains, thus meaning paths never need to be considered.
*
* This is a very basic optimization; anything further could have
* drawbacks depending on the setup, so this is best done per-installation.
*/
$using_paths = true;
if ( wp_using_ext_object_cache() ) {
$using_paths = get_networks(
array(
'number' => 1,
'count' => true,
'path__not_in' => '/',
)
);
}
$paths = array();
if ( $using_paths ) {
$path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
/**
* Filters the number of path segments to consider when searching for a site.
*
* @since 3.9.0
*
* @param int|null $segments The number of path segments to consider. WordPress by default looks at
* one path segment. The function default of null only makes sense when you
* know the requested path should match a network.
* @param string $domain The requested domain.
* @param string $path The requested path, in full.
*/
$segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path );
if ( ( null !== $segments ) && count( $path_segments ) > $segments ) {
$path_segments = array_slice( $path_segments, 0, $segments );
}
while ( count( $path_segments ) ) {
$paths[] = '/' . implode( '/', $path_segments ) . '/';
array_pop( $path_segments );
}
$paths[] = '/';
}
/**
* Determines a network by its domain and path.
*
* This allows one to short-circuit the default logic, perhaps by
* replacing it with a routine that is more optimal for your setup.
*
* Return null to avoid the short-circuit. Return false if no network
* can be found at the requested domain and path. Otherwise, return
* an object from wp_get_network().
*
* @since 3.9.0
*
* @param null|false|WP_Network $network Network value to return by path. Default null
* to continue retrieving the network.
* @param string $domain The requested domain.
* @param string $path The requested path, in full.
* @param int|null $segments The suggested number of paths to consult.
* Default null, meaning the entire path was to be consulted.
* @param string[] $paths Array of paths to search for, based on `$path` and `$segments`.
*/
$pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths );
if ( null !== $pre ) {
return $pre;
}
if ( ! $using_paths ) {
$networks = get_networks(
array(
'number' => 1,
'orderby' => array(
'domain_length' => 'DESC',
),
'domain__in' => $domains,
)
);
if ( ! empty( $networks ) ) {
return array_shift( $networks );
}
return false;
}
$networks = get_networks(
array(
'orderby' => array(
'domain_length' => 'DESC',
'path_length' => 'DESC',
),
'domain__in' => $domains,
'path__in' => $paths,
)
);
/*
* Domains are sorted by length of domain, then by length of path.
* The domain must match for the path to be considered. Otherwise,
* a network with the path of / will suffice.
*/
$found = false;
foreach ( $networks as $network ) {
if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) {
if ( in_array( $network->path, $paths, true ) ) {
$found = true;
break;
}
}
if ( '/' === $network->path ) {
$found = true;
break;
}
}
if ( true === $found ) {
return $network;
}
return false;
}
}
<?php
/**
* RSS 0.92 Feed Template for displaying RSS 0.92 Posts feed.
*
* @package WordPress
*/
header( 'Content-Type: ' . feed_content_type( 'rss' ) . '; charset=' . get_option( 'blog_charset' ), true );
$more = 1;
echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?>
<rss version="0.92">
<channel>
<title><?php wp_title_rss(); ?></title>
<link><?php bloginfo_rss( 'url' ); ?></link>
<description><?php bloginfo_rss( 'description' ); ?></description>
<lastBuildDate><?php echo get_feed_build_date( 'D, d M Y H:i:s +0000' ); ?></lastBuildDate>
<docs>http://backend.userland.com/rss092</docs>
<language><?php bloginfo_rss( 'language' ); ?></language>
<?php
/**
* Fires at the end of the RSS Feed Header.
*
* @since 2.0.0
*/
do_action( 'rss_head' );
?>
<?php
while ( have_posts() ) :
the_post();
?>
<item>
<title><?php the_title_rss(); ?></title>
<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
<link><?php the_permalink_rss(); ?></link>
<?php
/**
* Fires at the end of each RSS feed item.
*
* @since 2.0.0
*/
do_action( 'rss_item' );
?>
</item>
<?php endwhile; ?>
</channel>
</rss>
<?php
/**
* Sitemaps: WP_Sitemaps_Renderer class
*
* Responsible for rendering Sitemaps data to XML in accordance with sitemap protocol.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Class WP_Sitemaps_Renderer
*
* @since 5.5.0
*/
#[AllowDynamicProperties]
class WP_Sitemaps_Renderer {
/**
* XSL stylesheet for styling a sitemap for web browsers.
*
* @since 5.5.0
*
* @var string
*/
protected $stylesheet = '';
/**
* XSL stylesheet for styling a sitemap for web browsers.
*
* @since 5.5.0
*
* @var string
*/
protected $stylesheet_index = '';
/**
* WP_Sitemaps_Renderer constructor.
*
* @since 5.5.0
*/
public function __construct() {
$stylesheet_url = $this->get_sitemap_stylesheet_url();
if ( $stylesheet_url ) {
$this->stylesheet = '<?xml-stylesheet type="text/xsl" href="' . esc_url( $stylesheet_url ) . '" ?>';
}
$stylesheet_index_url = $this->get_sitemap_index_stylesheet_url();
if ( $stylesheet_index_url ) {
$this->stylesheet_index = '<?xml-stylesheet type="text/xsl" href="' . esc_url( $stylesheet_index_url ) . '" ?>';
}
}
/**
* Gets the URL for the sitemap stylesheet.
*
* @since 5.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @return string The sitemap stylesheet URL.
*/
public function get_sitemap_stylesheet_url() {
global $wp_rewrite;
$sitemap_url = home_url( '/wp-sitemap.xsl' );
if ( ! $wp_rewrite->using_permalinks() ) {
$sitemap_url = home_url( '/?sitemap-stylesheet=sitemap' );
}
/**
* Filters the URL for the sitemap stylesheet.
*
* If a falsey value is returned, no stylesheet will be used and
* the "raw" XML of the sitemap will be displayed.
*
* @since 5.5.0
*
* @param string $sitemap_url Full URL for the sitemaps XSL file.
*/
return apply_filters( 'wp_sitemaps_stylesheet_url', $sitemap_url );
}
/**
* Gets the URL for the sitemap index stylesheet.
*
* @since 5.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @return string The sitemap index stylesheet URL.
*/
public function get_sitemap_index_stylesheet_url() {
global $wp_rewrite;
$sitemap_url = home_url( '/wp-sitemap-index.xsl' );
if ( ! $wp_rewrite->using_permalinks() ) {
$sitemap_url = home_url( '/?sitemap-stylesheet=index' );
}
/**
* Filters the URL for the sitemap index stylesheet.
*
* If a falsey value is returned, no stylesheet will be used and
* the "raw" XML of the sitemap index will be displayed.
*
* @since 5.5.0
*
* @param string $sitemap_url Full URL for the sitemaps index XSL file.
*/
return apply_filters( 'wp_sitemaps_stylesheet_index_url', $sitemap_url );
}
/**
* Renders a sitemap index.
*
* @since 5.5.0
*
* @param array $sitemaps Array of sitemap URLs.
*/
public function render_index( $sitemaps ) {
header( 'Content-Type: application/xml; charset=UTF-8' );
$this->check_for_simple_xml_availability();
$index_xml = $this->get_sitemap_index_xml( $sitemaps );
if ( ! empty( $index_xml ) ) {
// All output is escaped within get_sitemap_index_xml().
echo $index_xml;
}
}
/**
* Gets XML for a sitemap index.
*
* @since 5.5.0
*
* @param array $sitemaps Array of sitemap URLs.
* @return string|false A well-formed XML string for a sitemap index. False on error.
*/
public function get_sitemap_index_xml( $sitemaps ) {
$sitemap_index = new SimpleXMLElement(
sprintf(
'%1$s%2$s%3$s',
'<?xml version="1.0" encoding="UTF-8" ?>',
$this->stylesheet_index,
'<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />'
)
);
foreach ( $sitemaps as $entry ) {
$sitemap = $sitemap_index->addChild( 'sitemap' );
// Add each element as a child node to the <sitemap> entry.
foreach ( $entry as $name => $value ) {
if ( 'loc' === $name ) {
$sitemap->addChild( $name, esc_url( $value ) );
} elseif ( 'lastmod' === $name ) {
$sitemap->addChild( $name, esc_xml( $value ) );
} else {
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: %s: List of element names. */
__( 'Fields other than %s are not currently supported for the sitemap index.' ),
implode( ',', array( 'loc', 'lastmod' ) )
),
'5.5.0'
);
}
}
}
return $sitemap_index->asXML();
}
/**
* Renders a sitemap.
*
* @since 5.5.0
*
* @param array $url_list Array of URLs for a sitemap.
*/
public function render_sitemap( $url_list ) {
header( 'Content-Type: application/xml; charset=UTF-8' );
$this->check_for_simple_xml_availability();
$sitemap_xml = $this->get_sitemap_xml( $url_list );
if ( ! empty( $sitemap_xml ) ) {
// All output is escaped within get_sitemap_xml().
echo $sitemap_xml;
}
}
/**
* Gets XML for a sitemap.
*
* @since 5.5.0
*
* @param array $url_list Array of URLs for a sitemap.
* @return string|false A well-formed XML string for a sitemap index. False on error.
*/
public function get_sitemap_xml( $url_list ) {
$urlset = new SimpleXMLElement(
sprintf(
'%1$s%2$s%3$s',
'<?xml version="1.0" encoding="UTF-8" ?>',
$this->stylesheet,
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />'
)
);
foreach ( $url_list as $url_item ) {
$url = $urlset->addChild( 'url' );
// Add each element as a child node to the <url> entry.
foreach ( $url_item as $name => $value ) {
if ( 'loc' === $name ) {
$url->addChild( $name, esc_url( $value ) );
} elseif ( in_array( $name, array( 'lastmod', 'changefreq', 'priority' ), true ) ) {
$url->addChild( $name, esc_xml( $value ) );
} else {
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: %s: List of element names. */
__( 'Fields other than %s are not currently supported for sitemaps.' ),
implode( ',', array( 'loc', 'lastmod', 'changefreq', 'priority' ) )
),
'5.5.0'
);
}
}
}
return $urlset->asXML();
}
/**
* Checks for the availability of the SimpleXML extension and errors if missing.
*
* @since 5.5.0
*/
private function check_for_simple_xml_availability() {
if ( ! class_exists( 'SimpleXMLElement' ) ) {
add_filter(
'wp_die_handler',
static function () {
return '_xml_wp_die_handler';
}
);
wp_die(
sprintf(
/* translators: %s: SimpleXML */
esc_xml( __( 'Could not generate XML sitemap due to missing %s extension' ) ),
'SimpleXML'
),
esc_xml( __( 'WordPress › Error' ) ),
array(
'response' => 501, // "Not implemented".
)
);
}
}
}
<?php
/**
* Sitemaps: WP_Sitemaps_Registry class
*
* Handles registering sitemap providers.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Class WP_Sitemaps_Registry.
*
* @since 5.5.0
*/
#[AllowDynamicProperties]
class WP_Sitemaps_Registry {
/**
* Registered sitemap providers.
*
* @since 5.5.0
*
* @var WP_Sitemaps_Provider[] Array of registered sitemap providers.
*/
private $providers = array();
/**
* Adds a new sitemap provider.
*
* @since 5.5.0
*
* @param string $name Name of the sitemap provider.
* @param WP_Sitemaps_Provider $provider Instance of a WP_Sitemaps_Provider.
* @return bool Whether the provider was added successfully.
*/
public function add_provider( $name, WP_Sitemaps_Provider $provider ) {
if ( isset( $this->providers[ $name ] ) ) {
return false;
}
/**
* Filters the sitemap provider before it is added.
*
* @since 5.5.0
*
* @param WP_Sitemaps_Provider $provider Instance of a WP_Sitemaps_Provider.
* @param string $name Name of the sitemap provider.
*/
$provider = apply_filters( 'wp_sitemaps_add_provider', $provider, $name );
if ( ! $provider instanceof WP_Sitemaps_Provider ) {
return false;
}
$this->providers[ $name ] = $provider;
return true;
}
/**
* Returns a single registered sitemap provider.
*
* @since 5.5.0
*
* @param string $name Sitemap provider name.
* @return WP_Sitemaps_Provider|null Sitemap provider if it exists, null otherwise.
*/
public function get_provider( $name ) {
if ( ! is_string( $name ) || ! isset( $this->providers[ $name ] ) ) {
return null;
}
return $this->providers[ $name ];
}
/**
* Returns all registered sitemap providers.
*
* @since 5.5.0
*
* @return WP_Sitemaps_Provider[] Array of sitemap providers.
*/
public function get_providers() {
return $this->providers;
}
}
<?php
/**
* Sitemaps: WP_Sitemaps_Index class.
*
* Generates the sitemap index.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Class WP_Sitemaps_Index.
* Builds the sitemap index page that lists the links to all of the sitemaps.
*
* @since 5.5.0
*/
#[AllowDynamicProperties]
class WP_Sitemaps_Index {
/**
* The main registry of supported sitemaps.
*
* @since 5.5.0
* @var WP_Sitemaps_Registry
*/
protected $registry;
/**
* Maximum number of sitemaps to include in an index.
*
* @since 5.5.0
*
* @var int Maximum number of sitemaps.
*/
private $max_sitemaps = 50000;
/**
* WP_Sitemaps_Index constructor.
*
* @since 5.5.0
*
* @param WP_Sitemaps_Registry $registry Sitemap provider registry.
*/
public function __construct( WP_Sitemaps_Registry $registry ) {
$this->registry = $registry;
}
/**
* Gets a sitemap list for the index.
*
* @since 5.5.0
*
* @return array[] Array of all sitemaps.
*/
public function get_sitemap_list() {
$sitemaps = array();
$providers = $this->registry->get_providers();
/* @var WP_Sitemaps_Provider $provider */
foreach ( $providers as $name => $provider ) {
$sitemap_entries = $provider->get_sitemap_entries();
// Prevent issues with array_push and empty arrays on PHP < 7.3.
if ( ! $sitemap_entries ) {
continue;
}
// Using array_push is more efficient than array_merge in a loop.
array_push( $sitemaps, ...$sitemap_entries );
if ( count( $sitemaps ) >= $this->max_sitemaps ) {
break;
}
}
return array_slice( $sitemaps, 0, $this->max_sitemaps, true );
}
/**
* Builds the URL for the sitemap index.
*
* @since 5.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @return string The sitemap index URL.
*/
public function get_index_url() {
global $wp_rewrite;
if ( ! $wp_rewrite->using_permalinks() ) {
return home_url( '/?sitemap=index' );
}
return home_url( '/wp-sitemap.xml' );
}
}
<?php
/**
* Sitemaps: WP_Sitemaps class
*
* This is the main class integrating all other classes.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Class WP_Sitemaps.
*
* @since 5.5.0
*/
#[AllowDynamicProperties]
class WP_Sitemaps {
/**
* The main index of supported sitemaps.
*
* @since 5.5.0
*
* @var WP_Sitemaps_Index
*/
public $index;
/**
* The main registry of supported sitemaps.
*
* @since 5.5.0
*
* @var WP_Sitemaps_Registry
*/
public $registry;
/**
* An instance of the renderer class.
*
* @since 5.5.0
*
* @var WP_Sitemaps_Renderer
*/
public $renderer;
/**
* WP_Sitemaps constructor.
*
* @since 5.5.0
*/
public function __construct() {
$this->registry = new WP_Sitemaps_Registry();
$this->renderer = new WP_Sitemaps_Renderer();
$this->index = new WP_Sitemaps_Index( $this->registry );
}
/**
* Initiates all sitemap functionality.
*
* If sitemaps are disabled, only the rewrite rules will be registered
* by this method, in order to properly send 404s.
*
* @since 5.5.0
*/
public function init() {
// These will all fire on the init hook.
$this->register_rewrites();
add_action( 'template_redirect', array( $this, 'render_sitemaps' ) );
if ( ! $this->sitemaps_enabled() ) {
return;
}
$this->register_sitemaps();
// Add additional action callbacks.
add_filter( 'robots_txt', array( $this, 'add_robots' ), 0, 2 );
}
/**
* Determines whether sitemaps are enabled or not.
*
* @since 5.5.0
*
* @return bool Whether sitemaps are enabled.
*/
public function sitemaps_enabled() {
$is_enabled = (bool) get_option( 'blog_public' );
/**
* Filters whether XML Sitemaps are enabled or not.
*
* When XML Sitemaps are disabled via this filter, rewrite rules are still
* in place to ensure a 404 is returned.
*
* @see WP_Sitemaps::register_rewrites()
*
* @since 5.5.0
*
* @param bool $is_enabled Whether XML Sitemaps are enabled or not.
* Defaults to true for public sites.
*/
return (bool) apply_filters( 'wp_sitemaps_enabled', $is_enabled );
}
/**
* Registers and sets up the functionality for all supported sitemaps.
*
* @since 5.5.0
*/
public function register_sitemaps() {
$providers = array(
'posts' => new WP_Sitemaps_Posts(),
'taxonomies' => new WP_Sitemaps_Taxonomies(),
'users' => new WP_Sitemaps_Users(),
);
/* @var WP_Sitemaps_Provider $provider */
foreach ( $providers as $name => $provider ) {
$this->registry->add_provider( $name, $provider );
}
}
/**
* Registers sitemap rewrite tags and routing rules.
*
* @since 5.5.0
*/
public function register_rewrites() {
// Add rewrite tags.
add_rewrite_tag( '%sitemap%', '([^?]+)' );
add_rewrite_tag( '%sitemap-subtype%', '([^?]+)' );
// Register index route.
add_rewrite_rule( '^wp-sitemap\.xml$', 'index.php?sitemap=index', 'top' );
// Register rewrites for the XSL stylesheet.
add_rewrite_tag( '%sitemap-stylesheet%', '([^?]+)' );
add_rewrite_rule( '^wp-sitemap\.xsl$', 'index.php?sitemap-stylesheet=sitemap', 'top' );
add_rewrite_rule( '^wp-sitemap-index\.xsl$', 'index.php?sitemap-stylesheet=index', 'top' );
// Register routes for providers.
add_rewrite_rule(
'^wp-sitemap-([a-z]+?)-([a-z\d_-]+?)-(\d+?)\.xml$',
'index.php?sitemap=$matches[1]&sitemap-subtype=$matches[2]&paged=$matches[3]',
'top'
);
add_rewrite_rule(
'^wp-sitemap-([a-z]+?)-(\d+?)\.xml$',
'index.php?sitemap=$matches[1]&paged=$matches[2]',
'top'
);
}
/**
* Renders sitemap templates based on rewrite rules.
*
* @since 5.5.0
*
* @global WP_Query $wp_query WordPress Query object.
*/
public function render_sitemaps() {
global $wp_query;
$sitemap = sanitize_text_field( get_query_var( 'sitemap' ) );
$object_subtype = sanitize_text_field( get_query_var( 'sitemap-subtype' ) );
$stylesheet_type = sanitize_text_field( get_query_var( 'sitemap-stylesheet' ) );
$paged = absint( get_query_var( 'paged' ) );
// Bail early if this isn't a sitemap or stylesheet route.
if ( ! ( $sitemap || $stylesheet_type ) ) {
return;
}
if ( ! $this->sitemaps_enabled() ) {
$wp_query->set_404();
status_header( 404 );
return;
}
// Render stylesheet if this is stylesheet route.
if ( $stylesheet_type ) {
$stylesheet = new WP_Sitemaps_Stylesheet();
$stylesheet->render_stylesheet( $stylesheet_type );
exit;
}
// Render the index.
if ( 'index' === $sitemap ) {
$sitemap_list = $this->index->get_sitemap_list();
$this->renderer->render_index( $sitemap_list );
exit;
}
$provider = $this->registry->get_provider( $sitemap );
if ( ! $provider ) {
return;
}
if ( empty( $paged ) ) {
$paged = 1;
}
$url_list = $provider->get_url_list( $paged, $object_subtype );
// Force a 404 and bail early if no URLs are present.
if ( empty( $url_list ) ) {
$wp_query->set_404();
status_header( 404 );
return;
}
$this->renderer->render_sitemap( $url_list );
exit;
}
/**
* Redirects a URL to the wp-sitemap.xml
*
* @since 5.5.0
* @deprecated 6.7.0 Deprecated in favor of {@see WP_Rewrite::rewrite_rules()}
*
* @param bool $bypass Pass-through of the pre_handle_404 filter value.
* @param WP_Query $query The WP_Query object.
* @return bool Bypass value.
*/
public function redirect_sitemapxml( $bypass, $query ) {
_deprecated_function( __FUNCTION__, '6.7.0' );
// If a plugin has already utilized the pre_handle_404 function, return without action to avoid conflicts.
if ( $bypass ) {
return $bypass;
}
// 'pagename' is for most permalink types, name is for when the %postname% is used as a top-level field.
if ( 'sitemap-xml' === $query->get( 'pagename' )
|| 'sitemap-xml' === $query->get( 'name' )
) {
wp_safe_redirect( $this->index->get_index_url() );
exit();
}
return $bypass;
}
/**
* Adds the sitemap index to robots.txt.
*
* @since 5.5.0
*
* @param string $output robots.txt output.
* @param bool $is_public Whether the site is public.
* @return string The robots.txt output.
*/
public function add_robots( $output, $is_public ) {
if ( $is_public ) {
$output .= "\nSitemap: " . esc_url( $this->index->get_index_url() ) . "\n";
}
return $output;
}
}
[02-Dec-2025 10:42:36 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Sitemaps_Provider" not found in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-users.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-users.php on line 17
[02-Dec-2025 10:42:36 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Sitemaps_Provider" not found in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-taxonomies.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-taxonomies.php on line 17
[02-Dec-2025 10:42:36 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Sitemaps_Provider" not found in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-posts.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-posts.php on line 17
[06-Mar-2026 11:40:47 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Sitemaps_Provider" not found in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-users.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-users.php on line 17
[06-Mar-2026 11:41:47 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Sitemaps_Provider" not found in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-posts.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-posts.php on line 17
[06-Mar-2026 16:00:04 America/Bogota] PHP Fatal error: Uncaught Error: Class "WP_Sitemaps_Provider" not found in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-taxonomies.php:17
Stack trace:
#0 {main}
thrown in /home/coopserp/public_html/wp-includes/sitemaps/providers/class-wp-sitemaps-taxonomies.php on line 17
<?php
/**
* Sitemaps: WP_Sitemaps_Users class
*
* Builds the sitemaps for the 'user' object type.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Users XML sitemap provider.
*
* @since 5.5.0
*/
class WP_Sitemaps_Users extends WP_Sitemaps_Provider {
/**
* WP_Sitemaps_Users constructor.
*
* @since 5.5.0
*/
public function __construct() {
$this->name = 'users';
$this->object_type = 'user';
}
/**
* Gets a URL list for a user sitemap.
*
* @since 5.5.0
*
* @param int $page_num Page of results.
* @param string $object_subtype Optional. Not applicable for Users but
* required for compatibility with the parent
* provider class. Default empty.
* @return array[] Array of URL information for a sitemap.
*/
public function get_url_list( $page_num, $object_subtype = '' ) {
/**
* Filters the users URL list before it is generated.
*
* Returning a non-null value will effectively short-circuit the generation,
* returning that value instead.
*
* @since 5.5.0
*
* @param array[]|null $url_list The URL list. Default null.
* @param int $page_num Page of results.
*/
$url_list = apply_filters(
'wp_sitemaps_users_pre_url_list',
null,
$page_num
);
if ( null !== $url_list ) {
return $url_list;
}
$args = $this->get_users_query_args();
$args['paged'] = $page_num;
$query = new WP_User_Query( $args );
$users = $query->get_results();
$url_list = array();
foreach ( $users as $user ) {
$sitemap_entry = array(
'loc' => get_author_posts_url( $user->ID ),
);
/**
* Filters the sitemap entry for an individual user.
*
* @since 5.5.0
*
* @param array $sitemap_entry Sitemap entry for the user.
* @param WP_User $user User object.
*/
$sitemap_entry = apply_filters( 'wp_sitemaps_users_entry', $sitemap_entry, $user );
$url_list[] = $sitemap_entry;
}
return $url_list;
}
/**
* Gets the max number of pages available for the object type.
*
* @since 5.5.0
*
* @see WP_Sitemaps_Provider::max_num_pages
*
* @param string $object_subtype Optional. Not applicable for Users but
* required for compatibility with the parent
* provider class. Default empty.
* @return int Total page count.
*/
public function get_max_num_pages( $object_subtype = '' ) {
/**
* Filters the max number of pages for a user sitemap before it is generated.
*
* Returning a non-null value will effectively short-circuit the generation,
* returning that value instead.
*
* @since 5.5.0
*
* @param int|null $max_num_pages The maximum number of pages. Default null.
*/
$max_num_pages = apply_filters( 'wp_sitemaps_users_pre_max_num_pages', null );
if ( null !== $max_num_pages ) {
return $max_num_pages;
}
$args = $this->get_users_query_args();
$query = new WP_User_Query( $args );
$total_users = $query->get_total();
return (int) ceil( $total_users / wp_sitemaps_get_max_urls( $this->object_type ) );
}
/**
* Returns the query args for retrieving users to list in the sitemap.
*
* @since 5.5.0
*
* @return array Array of WP_User_Query arguments.
*/
protected function get_users_query_args() {
$public_post_types = get_post_types(
array(
'public' => true,
)
);
// We're not supporting sitemaps for author pages for attachments and pages.
unset( $public_post_types['attachment'] );
unset( $public_post_types['page'] );
/**
* Filters the query arguments for authors with public posts.
*
* Allows modification of the authors query arguments before querying.
*
* @see WP_User_Query for a full list of arguments
*
* @since 5.5.0
*
* @param array $args Array of WP_User_Query arguments.
*/
$args = apply_filters(
'wp_sitemaps_users_query_args',
array(
'has_published_posts' => array_keys( $public_post_types ),
'number' => wp_sitemaps_get_max_urls( $this->object_type ),
)
);
return $args;
}
}
<?php
/**
* Sitemaps: WP_Sitemaps_Posts class
*
* Builds the sitemaps for the 'post' object type.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Posts XML sitemap provider.
*
* @since 5.5.0
*/
class WP_Sitemaps_Posts extends WP_Sitemaps_Provider {
/**
* WP_Sitemaps_Posts constructor.
*
* @since 5.5.0
*/
public function __construct() {
$this->name = 'posts';
$this->object_type = 'post';
}
/**
* Returns the public post types, which excludes nav_items and similar types.
* Attachments are also excluded. This includes custom post types with public = true.
*
* @since 5.5.0
*
* @return WP_Post_Type[] Array of registered post type objects keyed by their name.
*/
public function get_object_subtypes() {
$post_types = get_post_types( array( 'public' => true ), 'objects' );
unset( $post_types['attachment'] );
$post_types = array_filter( $post_types, 'is_post_type_viewable' );
/**
* Filters the list of post object sub types available within the sitemap.
*
* @since 5.5.0
*
* @param WP_Post_Type[] $post_types Array of registered post type objects keyed by their name.
*/
return apply_filters( 'wp_sitemaps_post_types', $post_types );
}
/**
* Gets a URL list for a post type sitemap.
*
* @since 5.5.0
* @since 5.9.0 Renamed `$post_type` to `$object_subtype` to match parent class
* for PHP 8 named parameter support.
*
* @param int $page_num Page of results.
* @param string $object_subtype Optional. Post type name. Default empty.
*
* @return array[] Array of URL information for a sitemap.
*/
public function get_url_list( $page_num, $object_subtype = '' ) {
// Restores the more descriptive, specific name for use within this method.
$post_type = $object_subtype;
// Bail early if the queried post type is not supported.
$supported_types = $this->get_object_subtypes();
if ( ! isset( $supported_types[ $post_type ] ) ) {
return array();
}
/**
* Filters the posts URL list before it is generated.
*
* Returning a non-null value will effectively short-circuit the generation,
* returning that value instead.
*
* @since 5.5.0
*
* @param array[]|null $url_list The URL list. Default null.
* @param string $post_type Post type name.
* @param int $page_num Page of results.
*/
$url_list = apply_filters(
'wp_sitemaps_posts_pre_url_list',
null,
$post_type,
$page_num
);
if ( null !== $url_list ) {
return $url_list;
}
$args = $this->get_posts_query_args( $post_type );
$args['paged'] = $page_num;
$query = new WP_Query( $args );
$url_list = array();
/*
* Add a URL for the homepage in the pages sitemap.
* Shows only on the first page if the reading settings are set to display latest posts.
*/
if ( 'page' === $post_type && 1 === $page_num && 'posts' === get_option( 'show_on_front' ) ) {
// Extract the data needed for home URL to add to the array.
$sitemap_entry = array(
'loc' => home_url( '/' ),
);
/*
* Get the most recent posts displayed on the homepage,
* and then sort them by their modified date to find
* the date the homepage was approximately last updated.
*/
$latest_posts = new WP_Query(
array(
'post_type' => 'post',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
)
);
if ( ! empty( $latest_posts->posts ) ) {
$posts = wp_list_sort( $latest_posts->posts, 'post_modified_gmt', 'DESC' );
$sitemap_entry['lastmod'] = wp_date( DATE_W3C, strtotime( $posts[0]->post_modified_gmt ) );
}
/**
* Filters the sitemap entry for the home page when the 'show_on_front' option equals 'posts'.
*
* @since 5.5.0
*
* @param array $sitemap_entry Sitemap entry for the home page.
*/
$sitemap_entry = apply_filters( 'wp_sitemaps_posts_show_on_front_entry', $sitemap_entry );
$url_list[] = $sitemap_entry;
}
foreach ( $query->posts as $post ) {
$sitemap_entry = array(
'loc' => get_permalink( $post ),
'lastmod' => wp_date( DATE_W3C, strtotime( $post->post_modified_gmt ) ),
);
/**
* Filters the sitemap entry for an individual post.
*
* @since 5.5.0
*
* @param array $sitemap_entry Sitemap entry for the post.
* @param WP_Post $post Post object.
* @param string $post_type Name of the post_type.
*/
$sitemap_entry = apply_filters( 'wp_sitemaps_posts_entry', $sitemap_entry, $post, $post_type );
$url_list[] = $sitemap_entry;
}
return $url_list;
}
/**
* Gets the max number of pages available for the object type.
*
* @since 5.5.0
* @since 5.9.0 Renamed `$post_type` to `$object_subtype` to match parent class
* for PHP 8 named parameter support.
*
* @param string $object_subtype Optional. Post type name. Default empty.
* @return int Total number of pages.
*/
public function get_max_num_pages( $object_subtype = '' ) {
if ( empty( $object_subtype ) ) {
return 0;
}
// Restores the more descriptive, specific name for use within this method.
$post_type = $object_subtype;
/**
* Filters the max number of pages before it is generated.
*
* Passing a non-null value will short-circuit the generation,
* returning that value instead.
*
* @since 5.5.0
*
* @param int|null $max_num_pages The maximum number of pages. Default null.
* @param string $post_type Post type name.
*/
$max_num_pages = apply_filters( 'wp_sitemaps_posts_pre_max_num_pages', null, $post_type );
if ( null !== $max_num_pages ) {
return $max_num_pages;
}
$args = $this->get_posts_query_args( $post_type );
$args['fields'] = 'ids';
$args['no_found_rows'] = false;
$query = new WP_Query( $args );
$min_num_pages = ( 'page' === $post_type && 'posts' === get_option( 'show_on_front' ) ) ? 1 : 0;
return isset( $query->max_num_pages ) ? max( $min_num_pages, $query->max_num_pages ) : 1;
}
/**
* Returns the query args for retrieving posts to list in the sitemap.
*
* @since 5.5.0
* @since 6.1.0 Added `ignore_sticky_posts` default parameter.
*
* @param string $post_type Post type name.
* @return array Array of WP_Query arguments.
*/
protected function get_posts_query_args( $post_type ) {
/**
* Filters the query arguments for post type sitemap queries.
*
* @see WP_Query for a full list of arguments.
*
* @since 5.5.0
* @since 6.1.0 Added `ignore_sticky_posts` default parameter.
*
* @param array $args Array of WP_Query arguments.
* @param string $post_type Post type name.
*/
$args = apply_filters(
'wp_sitemaps_posts_query_args',
array(
'orderby' => 'ID',
'order' => 'ASC',
'post_type' => $post_type,
'posts_per_page' => wp_sitemaps_get_max_urls( $this->object_type ),
'post_status' => array( 'publish' ),
'no_found_rows' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'ignore_sticky_posts' => true, // Sticky posts will still appear, but they won't be moved to the front.
),
$post_type
);
return $args;
}
}
<?php
/**
* Sitemaps: WP_Sitemaps_Taxonomies class
*
* Builds the sitemaps for the 'taxonomy' object type.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Taxonomies XML sitemap provider.
*
* @since 5.5.0
*/
class WP_Sitemaps_Taxonomies extends WP_Sitemaps_Provider {
/**
* WP_Sitemaps_Taxonomies constructor.
*
* @since 5.5.0
*/
public function __construct() {
$this->name = 'taxonomies';
$this->object_type = 'term';
}
/**
* Returns all public, registered taxonomies.
*
* @since 5.5.0
*
* @return WP_Taxonomy[] Array of registered taxonomy objects keyed by their name.
*/
public function get_object_subtypes() {
$taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
$taxonomies = array_filter( $taxonomies, 'is_taxonomy_viewable' );
/**
* Filters the list of taxonomy object subtypes available within the sitemap.
*
* @since 5.5.0
*
* @param WP_Taxonomy[] $taxonomies Array of registered taxonomy objects keyed by their name.
*/
return apply_filters( 'wp_sitemaps_taxonomies', $taxonomies );
}
/**
* Gets a URL list for a taxonomy sitemap.
*
* @since 5.5.0
* @since 5.9.0 Renamed `$taxonomy` to `$object_subtype` to match parent class
* for PHP 8 named parameter support.
*
* @param int $page_num Page of results.
* @param string $object_subtype Optional. Taxonomy name. Default empty.
* @return array[] Array of URL information for a sitemap.
*/
public function get_url_list( $page_num, $object_subtype = '' ) {
// Restores the more descriptive, specific name for use within this method.
$taxonomy = $object_subtype;
$supported_types = $this->get_object_subtypes();
// Bail early if the queried taxonomy is not supported.
if ( ! isset( $supported_types[ $taxonomy ] ) ) {
return array();
}
/**
* Filters the taxonomies URL list before it is generated.
*
* Returning a non-null value will effectively short-circuit the generation,
* returning that value instead.
*
* @since 5.5.0
*
* @param array[]|null $url_list The URL list. Default null.
* @param string $taxonomy Taxonomy name.
* @param int $page_num Page of results.
*/
$url_list = apply_filters(
'wp_sitemaps_taxonomies_pre_url_list',
null,
$taxonomy,
$page_num
);
if ( null !== $url_list ) {
return $url_list;
}
$url_list = array();
// Offset by how many terms should be included in previous pages.
$offset = ( $page_num - 1 ) * wp_sitemaps_get_max_urls( $this->object_type );
$args = $this->get_taxonomies_query_args( $taxonomy );
$args['fields'] = 'all';
$args['offset'] = $offset;
$taxonomy_terms = new WP_Term_Query( $args );
if ( ! empty( $taxonomy_terms->terms ) ) {
foreach ( $taxonomy_terms->terms as $term ) {
$term_link = get_term_link( $term, $taxonomy );
if ( is_wp_error( $term_link ) ) {
continue;
}
$sitemap_entry = array(
'loc' => $term_link,
);
/**
* Filters the sitemap entry for an individual term.
*
* @since 5.5.0
* @since 6.0.0 Added `$term` argument containing the term object.
*
* @param array $sitemap_entry Sitemap entry for the term.
* @param int $term_id Term ID.
* @param string $taxonomy Taxonomy name.
* @param WP_Term $term Term object.
*/
$sitemap_entry = apply_filters( 'wp_sitemaps_taxonomies_entry', $sitemap_entry, $term->term_id, $taxonomy, $term );
$url_list[] = $sitemap_entry;
}
}
return $url_list;
}
/**
* Gets the max number of pages available for the object type.
*
* @since 5.5.0
* @since 5.9.0 Renamed `$taxonomy` to `$object_subtype` to match parent class
* for PHP 8 named parameter support.
*
* @param string $object_subtype Optional. Taxonomy name. Default empty.
* @return int Total number of pages.
*/
public function get_max_num_pages( $object_subtype = '' ) {
if ( empty( $object_subtype ) ) {
return 0;
}
// Restores the more descriptive, specific name for use within this method.
$taxonomy = $object_subtype;
/**
* Filters the max number of pages for a taxonomy sitemap before it is generated.
*
* Passing a non-null value will short-circuit the generation,
* returning that value instead.
*
* @since 5.5.0
*
* @param int|null $max_num_pages The maximum number of pages. Default null.
* @param string $taxonomy Taxonomy name.
*/
$max_num_pages = apply_filters( 'wp_sitemaps_taxonomies_pre_max_num_pages', null, $taxonomy );
if ( null !== $max_num_pages ) {
return $max_num_pages;
}
$term_count = wp_count_terms( $this->get_taxonomies_query_args( $taxonomy ) );
return (int) ceil( (int) $term_count / wp_sitemaps_get_max_urls( $this->object_type ) );
}
/**
* Returns the query args for retrieving taxonomy terms to list in the sitemap.
*
* @since 5.5.0
*
* @param string $taxonomy Taxonomy name.
* @return array Array of WP_Term_Query arguments.
*/
protected function get_taxonomies_query_args( $taxonomy ) {
/**
* Filters the taxonomy terms query arguments.
*
* Allows modification of the taxonomy query arguments before querying.
*
* @see WP_Term_Query for a full list of arguments
*
* @since 5.5.0
*
* @param array $args Array of WP_Term_Query arguments.
* @param string $taxonomy Taxonomy name.
*/
$args = apply_filters(
'wp_sitemaps_taxonomies_query_args',
array(
'taxonomy' => $taxonomy,
'orderby' => 'term_order',
'number' => wp_sitemaps_get_max_urls( $this->object_type ),
'hide_empty' => true,
'hierarchical' => false,
'update_term_meta_cache' => false,
),
$taxonomy
);
return $args;
}
}
<?php
/**
* Sitemaps: WP_Sitemaps_Provider class
*
* This class is a base class for other sitemap providers to extend and contains shared functionality.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Class WP_Sitemaps_Provider.
*
* @since 5.5.0
*/
#[AllowDynamicProperties]
abstract class WP_Sitemaps_Provider {
/**
* Provider name.
*
* This will also be used as the public-facing name in URLs.
*
* @since 5.5.0
*
* @var string
*/
protected $name = '';
/**
* Object type name (e.g. 'post', 'term', 'user').
*
* @since 5.5.0
*
* @var string
*/
protected $object_type = '';
/**
* Gets a URL list for a sitemap.
*
* @since 5.5.0
*
* @param int $page_num Page of results.
* @param string $object_subtype Optional. Object subtype name. Default empty.
* @return array[] Array of URL information for a sitemap.
*/
abstract public function get_url_list( $page_num, $object_subtype = '' );
/**
* Gets the max number of pages available for the object type.
*
* @since 5.5.0
*
* @param string $object_subtype Optional. Object subtype. Default empty.
* @return int Total number of pages.
*/
abstract public function get_max_num_pages( $object_subtype = '' );
/**
* Gets data about each sitemap type.
*
* @since 5.5.0
*
* @return array[] Array of sitemap types including object subtype name and number of pages.
*/
public function get_sitemap_type_data() {
$sitemap_data = array();
$object_subtypes = $this->get_object_subtypes();
/*
* If there are no object subtypes, include a single sitemap for the
* entire object type.
*/
if ( empty( $object_subtypes ) ) {
$sitemap_data[] = array(
'name' => '',
'pages' => $this->get_max_num_pages(),
);
return $sitemap_data;
}
// Otherwise, include individual sitemaps for every object subtype.
foreach ( $object_subtypes as $object_subtype_name => $data ) {
$object_subtype_name = (string) $object_subtype_name;
$sitemap_data[] = array(
'name' => $object_subtype_name,
'pages' => $this->get_max_num_pages( $object_subtype_name ),
);
}
return $sitemap_data;
}
/**
* Lists sitemap pages exposed by this provider.
*
* The returned data is used to populate the sitemap entries of the index.
*
* @since 5.5.0
*
* @return array[] Array of sitemap entries.
*/
public function get_sitemap_entries() {
$sitemaps = array();
$sitemap_types = $this->get_sitemap_type_data();
foreach ( $sitemap_types as $type ) {
for ( $page = 1; $page <= $type['pages']; $page++ ) {
$sitemap_entry = array(
'loc' => $this->get_sitemap_url( $type['name'], $page ),
);
/**
* Filters the sitemap entry for the sitemap index.
*
* @since 5.5.0
*
* @param array $sitemap_entry Sitemap entry for the post.
* @param string $object_type Object empty name.
* @param string $object_subtype Object subtype name.
* Empty string if the object type does not support subtypes.
* @param int $page Page number of results.
*/
$sitemap_entry = apply_filters( 'wp_sitemaps_index_entry', $sitemap_entry, $this->object_type, $type['name'], $page );
$sitemaps[] = $sitemap_entry;
}
}
return $sitemaps;
}
/**
* Gets the URL of a sitemap entry.
*
* @since 5.5.0
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param string $name The name of the sitemap.
* @param int $page The page of the sitemap.
* @return string The composed URL for a sitemap entry.
*/
public function get_sitemap_url( $name, $page ) {
global $wp_rewrite;
// Accounts for cases where name is not included, ex: sitemaps-users-1.xml.
$params = array_filter(
array(
'sitemap' => $this->name,
'sitemap-subtype' => $name,
'paged' => $page,
)
);
$basename = sprintf(
'/wp-sitemap-%1$s.xml',
implode( '-', $params )
);
if ( ! $wp_rewrite->using_permalinks() ) {
$basename = '/?' . http_build_query( $params, '', '&' );
}
return home_url( $basename );
}
/**
* Returns the list of supported object subtypes exposed by the provider.
*
* @since 5.5.0
*
* @return array List of object subtypes objects keyed by their name.
*/
public function get_object_subtypes() {
return array();
}
}
<?php
/**
* Sitemaps: WP_Sitemaps_Stylesheet class
*
* This class provides the XSL stylesheets to style all sitemaps.
*
* @package WordPress
* @subpackage Sitemaps
* @since 5.5.0
*/
/**
* Stylesheet provider class.
*
* @since 5.5.0
*/
#[AllowDynamicProperties]
class WP_Sitemaps_Stylesheet {
/**
* Renders the XSL stylesheet depending on whether it's the sitemap index or not.
*
* @param string $type Stylesheet type. Either 'sitemap' or 'index'.
*/
public function render_stylesheet( $type ) {
header( 'Content-Type: application/xml; charset=UTF-8' );
if ( 'sitemap' === $type ) {
// All content is escaped below.
echo $this->get_sitemap_stylesheet();
}
if ( 'index' === $type ) {
// All content is escaped below.
echo $this->get_sitemap_index_stylesheet();
}
exit;
}
/**
* Returns the escaped XSL for all sitemaps, except index.
*
* @since 5.5.0
*/
public function get_sitemap_stylesheet() {
$css = $this->get_stylesheet_css();
$title = esc_xml( __( 'XML Sitemap' ) );
$description = esc_xml( __( 'This XML Sitemap is generated by WordPress to make your content more visible for search engines.' ) );
$learn_more = sprintf(
'<a href="%s">%s</a>',
esc_url( __( 'https://www.sitemaps.org/' ) ),
esc_xml( __( 'Learn more about XML sitemaps.' ) )
);
$text = sprintf(
/* translators: %s: Number of URLs. */
esc_xml( __( 'Number of URLs in this XML Sitemap: %s.' ) ),
'<xsl:value-of select="count( sitemap:urlset/sitemap:url )" />'
);
$lang = get_language_attributes( 'html' );
$url = esc_xml( __( 'URL' ) );
$lastmod = esc_xml( __( 'Last Modified' ) );
$changefreq = esc_xml( __( 'Change Frequency' ) );
$priority = esc_xml( __( 'Priority' ) );
$xsl_content = <<<XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
exclude-result-prefixes="sitemap"
>
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<!--
Set variables for whether lastmod, changefreq or priority occur for any url in the sitemap.
We do this up front because it can be expensive in a large sitemap.
-->
<xsl:variable name="has-lastmod" select="count( /sitemap:urlset/sitemap:url/sitemap:lastmod )" />
<xsl:variable name="has-changefreq" select="count( /sitemap:urlset/sitemap:url/sitemap:changefreq )" />
<xsl:variable name="has-priority" select="count( /sitemap:urlset/sitemap:url/sitemap:priority )" />
<xsl:template match="/">
<html {$lang}>
<head>
<title>{$title}</title>
<style>
{$css}
</style>
</head>
<body>
<div id="sitemap">
<div id="sitemap__header">
<h1>{$title}</h1>
<p>{$description}</p>
<p>{$learn_more}</p>
</div>
<div id="sitemap__content">
<p class="text">{$text}</p>
<table id="sitemap__table">
<thead>
<tr>
<th class="loc">{$url}</th>
<xsl:if test="\$has-lastmod">
<th class="lastmod">{$lastmod}</th>
</xsl:if>
<xsl:if test="\$has-changefreq">
<th class="changefreq">{$changefreq}</th>
</xsl:if>
<xsl:if test="\$has-priority">
<th class="priority">{$priority}</th>
</xsl:if>
</tr>
</thead>
<tbody>
<xsl:for-each select="sitemap:urlset/sitemap:url">
<tr>
<td class="loc"><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc" /></a></td>
<xsl:if test="\$has-lastmod">
<td class="lastmod"><xsl:value-of select="sitemap:lastmod" /></td>
</xsl:if>
<xsl:if test="\$has-changefreq">
<td class="changefreq"><xsl:value-of select="sitemap:changefreq" /></td>
</xsl:if>
<xsl:if test="\$has-priority">
<td class="priority"><xsl:value-of select="sitemap:priority" /></td>
</xsl:if>
</tr>
</xsl:for-each>
</tbody>
</table>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
XSL;
/**
* Filters the content of the sitemap stylesheet.
*
* @since 5.5.0
*
* @param string $xsl_content Full content for the XML stylesheet.
*/
return apply_filters( 'wp_sitemaps_stylesheet_content', $xsl_content );
}
/**
* Returns the escaped XSL for the index sitemaps.
*
* @since 5.5.0
*/
public function get_sitemap_index_stylesheet() {
$css = $this->get_stylesheet_css();
$title = esc_xml( __( 'XML Sitemap' ) );
$description = esc_xml( __( 'This XML Sitemap is generated by WordPress to make your content more visible for search engines.' ) );
$learn_more = sprintf(
'<a href="%s">%s</a>',
esc_url( __( 'https://www.sitemaps.org/' ) ),
esc_xml( __( 'Learn more about XML sitemaps.' ) )
);
$text = sprintf(
/* translators: %s: Number of URLs. */
esc_xml( __( 'Number of URLs in this XML Sitemap: %s.' ) ),
'<xsl:value-of select="count( sitemap:sitemapindex/sitemap:sitemap )" />'
);
$lang = get_language_attributes( 'html' );
$url = esc_xml( __( 'URL' ) );
$lastmod = esc_xml( __( 'Last Modified' ) );
$xsl_content = <<<XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
exclude-result-prefixes="sitemap"
>
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<!--
Set variables for whether lastmod occurs for any sitemap in the index.
We do this up front because it can be expensive in a large sitemap.
-->
<xsl:variable name="has-lastmod" select="count( /sitemap:sitemapindex/sitemap:sitemap/sitemap:lastmod )" />
<xsl:template match="/">
<html {$lang}>
<head>
<title>{$title}</title>
<style>
{$css}
</style>
</head>
<body>
<div id="sitemap">
<div id="sitemap__header">
<h1>{$title}</h1>
<p>{$description}</p>
<p>{$learn_more}</p>
</div>
<div id="sitemap__content">
<p class="text">{$text}</p>
<table id="sitemap__table">
<thead>
<tr>
<th class="loc">{$url}</th>
<xsl:if test="\$has-lastmod">
<th class="lastmod">{$lastmod}</th>
</xsl:if>
</tr>
</thead>
<tbody>
<xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
<tr>
<td class="loc"><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc" /></a></td>
<xsl:if test="\$has-lastmod">
<td class="lastmod"><xsl:value-of select="sitemap:lastmod" /></td>
</xsl:if>
</tr>
</xsl:for-each>
</tbody>
</table>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
XSL;
/**
* Filters the content of the sitemap index stylesheet.
*
* @since 5.5.0
*
* @param string $xsl_content Full content for the XML stylesheet.
*/
return apply_filters( 'wp_sitemaps_stylesheet_index_content', $xsl_content );
}
/**
* Gets the CSS to be included in sitemap XSL stylesheets.
*
* @since 5.5.0
*
* @return string The CSS.
*/
public function get_stylesheet_css() {
$text_align = is_rtl() ? 'right' : 'left';
$css = <<<EOF
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
color: #444;
}
#sitemap {
max-width: 980px;
margin: 0 auto;
}
#sitemap__table {
width: 100%;
border: solid 1px #ccc;
border-collapse: collapse;
}
#sitemap__table tr td.loc {
/*
* URLs should always be LTR.
* See https://core.trac.wordpress.org/ticket/16834
* and https://core.trac.wordpress.org/ticket/49949
*/
direction: ltr;
}
#sitemap__table tr th {
text-align: {$text_align};
}
#sitemap__table tr td,
#sitemap__table tr th {
padding: 10px;
}
#sitemap__table tr:nth-child(odd) td {
background-color: #eee;
}
a:hover {
text-decoration: none;
}
EOF;
/**
* Filters the CSS only for the sitemap stylesheet.
*
* @since 5.5.0
*
* @param string $css CSS to be applied to default XSL file.
*/
return apply_filters( 'wp_sitemaps_stylesheet_css', $css );
}
}
/*! This file is auto-generated */
.wp-pointer-content {
padding: 0 0 10px;
position: relative;
font-size: 13px;
background: #fff;
border: 1px solid #c3c4c7;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08);
}
.wp-pointer-content h3 {
position: relative;
margin: -1px -1px 5px;
padding: 15px 60px 14px 18px;
border: 1px solid #2271b1;
border-bottom: none;
line-height: 1.4;
font-size: 14px;
color: #fff;
background: #2271b1;
}
.wp-pointer-content h3:before {
background: #fff;
border-radius: 50%;
color: #2271b1;
content: "\f227";
font: normal 20px/1.6 dashicons;
position: absolute;
top: 8px;
right: 15px;
speak: never;
text-align: center;
width: 32px;
height: 32px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.wp-pointer-content h4 {
margin: 1.33em 20px 1em;
font-size: 1.15em;
}
.wp-pointer-content p {
padding: 0 20px;
}
.wp-pointer-buttons {
margin: 0;
padding: 5px 15px;
overflow: auto;
}
.wp-pointer-buttons a {
float: left;
display: inline-block;
text-decoration: none;
}
.wp-pointer-buttons a.close {
padding-right: 3px;
position: relative;
}
.wp-pointer-buttons a.close:before {
background: none;
color: #787c82;
content: "\f153";
display: block !important;
font: normal 16px/1 dashicons;
speak: never;
margin: 1px 0;
text-align: center;
-webkit-font-smoothing: antialiased !important;
width: 10px;
height: 100%;
position: absolute;
right: -15px;
top: 1px;
}
.wp-pointer-buttons a.close:hover:before {
color: #d63638;
}
/* The arrow base class must take up no space, even with transparent borders. */
.wp-pointer-arrow,
.wp-pointer-arrow-inner {
position: absolute;
width: 0;
height: 0;
}
.wp-pointer-arrow {
z-index: 10;
width: 0;
height: 0;
border: 0 solid transparent;
}
.wp-pointer-arrow-inner {
z-index: 20;
}
/* Make Room for the Arrow! */
.wp-pointer-top,
.wp-pointer-undefined {
padding-top: 13px;
}
.wp-pointer-bottom {
margin-top: -13px;
padding-bottom: 13px;
}
/* rtl:ignore */
.wp-pointer-left {
padding-left: 13px;
}
/* rtl:ignore */
.wp-pointer-right {
margin-left: -13px;
padding-right: 13px;
}
/* Base Size & Positioning */
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-bottom .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
right: 50px;
}
.wp-pointer-left .wp-pointer-arrow,
.wp-pointer-right .wp-pointer-arrow {
top: 50%;
margin-top: -15px;
}
/* Arrow Sprite */
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
top: 0;
border-width: 0 13px 13px;
border-bottom-color: #2271b1;
}
.wp-pointer-top .wp-pointer-arrow-inner,
.wp-pointer-undefined .wp-pointer-arrow-inner {
top: 1px;
margin-right: -13px;
margin-top: -13px;
border: 13px solid transparent;
border-bottom-color: #2271b1;
display: block;
content: " ";
}
.wp-pointer-bottom .wp-pointer-arrow {
bottom: 0;
border-width: 13px 13px 0;
border-top-color: #c3c4c7;
}
.wp-pointer-bottom .wp-pointer-arrow-inner {
bottom: 1px;
margin-right: -13px;
margin-bottom: -13px;
border: 13px solid transparent;
border-top-color: #fff;
display: block;
content: " ";
}
/* rtl:ignore */
.wp-pointer-left .wp-pointer-arrow {
left: 0;
border-width: 13px 13px 13px 0;
border-right-color: #c3c4c7;
}
/* rtl:ignore */
.wp-pointer-left .wp-pointer-arrow-inner {
left: 1px;
margin-left: -13px;
margin-top: -13px;
border: 13px solid transparent;
border-right-color: #fff;
display: block;
content: " ";
}
/* rtl:ignore */
.wp-pointer-right .wp-pointer-arrow {
right: 0;
border-width: 13px 0 13px 13px;
border-left-color: #c3c4c7;
}
/* rtl:ignore */
.wp-pointer-right .wp-pointer-arrow-inner {
right: 1px;
margin-right: -13px;
margin-top: -13px;
border: 13px solid transparent;
border-left-color: #fff;
display: block;
content: " ";
}
.wp-pointer.arrow-bottom .wp-pointer-content {
margin-bottom: -45px;
}
.wp-pointer.arrow-bottom .wp-pointer-arrow {
top: 100%;
margin-top: -30px;
}
/* Disable pointers at responsive sizes */
@media screen and (max-width: 782px) {
.wp-pointer {
display: none;
}
}
/*!
* jQuery UI CSS Framework 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden {
display: none;
}
.ui-helper-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.ui-helper-reset {
margin: 0;
padding: 0;
border: 0;
outline: 0;
line-height: 1.3;
text-decoration: none;
font-size: 100%;
list-style: none;
}
.ui-helper-clearfix:before,
.ui-helper-clearfix:after {
content: "";
display: table;
border-collapse: collapse;
}
.ui-helper-clearfix:after {
clear: both;
}
.ui-helper-clearfix {
min-height: 0; /* support: IE7 */
}
.ui-helper-zfix {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0); /* support: IE8 */
}
.ui-front {
z-index: 100;
}
/* Interaction Cues
----------------------------------*/
.ui-state-disabled {
cursor: default !important;
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
display: block;
text-indent: -99999px;
overflow: hidden;
background-repeat: no-repeat;
}
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/*!
* jQuery UI Resizable 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
.ui-resizable {
position: relative;
}
.ui-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
touch-action: none;
}
.ui-resizable-disabled .ui-resizable-handle,
.ui-resizable-autohide .ui-resizable-handle {
display: none;
}
.ui-resizable-n {
cursor: n-resize;
height: 7px;
width: 100%;
top: -5px;
left: 0;
}
.ui-resizable-s {
cursor: s-resize;
height: 7px;
width: 100%;
bottom: -5px;
left: 0;
}
/* rtl:ignore */
.ui-resizable-e {
cursor: e-resize;
width: 7px;
right: -5px;
top: 0;
height: 100%;
}
/* rtl:ignore */
.ui-resizable-w {
cursor: w-resize;
width: 7px;
left: -5px;
top: 0;
height: 100%;
}
/* rtl:ignore */
.ui-resizable-se {
cursor: se-resize;
width: 12px;
height: 12px;
right: 1px;
bottom: 1px;
}
/* rtl:ignore */
.ui-resizable-sw {
cursor: sw-resize;
width: 9px;
height: 9px;
left: -5px;
bottom: -5px;
}
/* rtl:ignore */
.ui-resizable-nw {
cursor: nw-resize;
width: 9px;
height: 9px;
left: -5px;
top: -5px;
}
/* rtl:ignore */
.ui-resizable-ne {
cursor: ne-resize;
width: 9px;
height: 9px;
right: -5px;
top: -5px;
}
/* WP buttons: see buttons.css. */
.ui-button {
display: inline-block;
text-decoration: none;
font-size: 13px;
line-height: 2;
height: 28px;
margin: 0;
padding: 0 10px 1px;
cursor: pointer;
border-width: 1px;
border-style: solid;
-webkit-appearance: none;
border-radius: 3px;
white-space: nowrap;
box-sizing: border-box;
color: #50575e;
border-color: #c3c4c7;
background: #f6f7f7;
box-shadow: 0 1px 0 #c3c4c7;
vertical-align: top;
}
.ui-button:active,
.ui-button:focus {
outline: none;
}
/* Remove the dotted border on :focus and the extra padding in Firefox */
.ui-button::-moz-focus-inner {
border-width: 0;
border-style: none;
padding: 0;
}
.ui-button:hover,
.ui-button:focus {
background: #f6f7f7;
border-color: #8c8f94;
color: #1d2327;
}
.ui-button:focus {
border-color: #4f94d4;
box-shadow: 0 0 3px rgba(34, 113, 177, 0.8);
}
.ui-button:active {
background: #f0f0f1;
border-color: #8c8f94;
box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
}
.ui-button[disabled],
.ui-button:disabled {
color: #a7aaad !important;
border-color: #dcdcde !important;
background: #f6f7f7 !important;
box-shadow: none !important;
text-shadow: 0 1px 0 #fff !important;
cursor: default;
transform: none !important;
}
@media screen and (max-width: 782px) {
.ui-button {
padding: 6px 14px;
line-height: normal;
font-size: 14px;
vertical-align: middle;
height: auto;
margin-bottom: 4px;
}
}
/* WP Theme */
.ui-dialog {
position: absolute;
top: 0;
left: 0;
z-index: 100102;
background-color: #fff;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.ui-dialog-titlebar {
background: #fff;
border-bottom: 1px solid #dcdcde;
height: 36px;
font-size: 18px;
font-weight: 600;
line-height: 2;
padding: 0 36px 0 16px;
}
.ui-button.ui-dialog-titlebar-close {
background: none;
border: none;
box-shadow: none;
color: #646970;
cursor: pointer;
display: block;
padding: 0;
position: absolute;
top: 0;
right: 0;
width: 36px;
height: 36px;
text-align: center;
border-radius: 0;
overflow: hidden;
}
.ui-dialog-titlebar-close:before {
font: normal 20px/1 dashicons;
vertical-align: top;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
line-height: 1.8;
width: 36px;
height: 36px;
content: "\f158";
}
.ui-button.ui-dialog-titlebar-close:hover,
.ui-button.ui-dialog-titlebar-close:focus {
color: #135e96;
}
.ui-button.ui-dialog-titlebar-close:focus {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -2px;
}
.ui-dialog-content {
padding: 16px;
overflow: auto;
}
.ui-dialog-buttonpane {
background: #fff;
border-top: 1px solid #dcdcde;
padding: 16px;
}
.ui-dialog-buttonpane .ui-button {
margin-left: 16px;
}
.ui-dialog-buttonpane .ui-dialog-buttonset {
float: right;
}
.ui-draggable .ui-dialog-titlebar {
cursor: move;
}
.ui-widget-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
min-height: 360px;
background: #000;
opacity: 0.7;
filter: alpha(opacity=70);
z-index: 100101;
}
/*! This file is auto-generated */
.customize-partial-refreshing{opacity:.25;transition:opacity .25s;cursor:progress}.customize-partial-refreshing.widget-customizer-highlighted-widget{box-shadow:none}.customize-partial-edit-shortcut,.widget .customize-partial-edit-shortcut{position:absolute;float:right;width:1px;height:1px;padding:0;margin:-1px -1px 0 0;border:0;background:0 0;color:transparent;box-shadow:none;outline:0;z-index:5}.customize-partial-edit-shortcut button,.widget .customize-partial-edit-shortcut button{position:absolute;right:-30px;top:2px;color:#fff;width:30px;height:30px;min-width:30px;min-height:30px;line-height:1!important;font-size:18px;z-index:5;background:#3582c4!important;border-radius:50%;border:2px solid #fff;box-shadow:0 2px 1px rgba(60,67,74,.15);text-align:center;cursor:pointer;box-sizing:border-box;padding:3px;animation-fill-mode:both;animation-duration:.4s;opacity:0;pointer-events:none;text-shadow:0 -1px 1px #135e96,-1px 0 1px #135e96,0 1px 1px #135e96,1px 0 1px #135e96}.wp-custom-header .customize-partial-edit-shortcut button{right:2px}.customize-partial-edit-shortcut button svg{fill:#fff;min-width:20px;min-height:20px;width:20px;height:20px;margin:auto}.customize-partial-edit-shortcut button:hover{background:#4f94d4!important}.customize-partial-edit-shortcut button:focus{box-shadow:0 0 0 2px #4f94d4}body.customize-partial-edit-shortcuts-shown .customize-partial-edit-shortcut button{animation-name:customize-partial-edit-shortcut-bounce-appear;pointer-events:auto}body.customize-partial-edit-shortcuts-hidden .customize-partial-edit-shortcut button{animation-name:customize-partial-edit-shortcut-bounce-disappear;pointer-events:none}.customize-partial-edit-shortcut-hidden .customize-partial-edit-shortcut button,.page-sidebar-collapsed .customize-partial-edit-shortcut button{visibility:hidden}@keyframes customize-partial-edit-shortcut-bounce-appear{20%,40%,60%,80%,from,to{animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;transform:scale3d(.3,.3,.3)}20%{transform:scale3d(1.1,1.1,1.1)}40%{transform:scale3d(.9,.9,.9)}60%{opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{transform:scale3d(.97,.97,.97)}to{opacity:1;transform:scale3d(1,1,1)}}@keyframes customize-partial-edit-shortcut-bounce-disappear{20%,40%,60%,80%,from,to{animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:1;transform:scale3d(1,1,1)}20%{transform:scale3d(.97,.97,.97)}40%{opacity:1;transform:scale3d(1.03,1.03,1.03)}60%{transform:scale3d(.9,.9,.9)}80%{transform:scale3d(1.1,1.1,1.1)}to{opacity:0;transform:scale3d(.3,.3,.3)}}@media screen and (max-width:800px){.customize-partial-edit-shortcut button,.widget .customize-partial-edit-shortcut button{right:-32px}}@media screen and (max-width:320px){.customize-partial-edit-shortcut button,.widget .customize-partial-edit-shortcut button{right:-30px}}/*! This file is auto-generated */
html {
--wp-admin--admin-bar--height: 32px;
scroll-padding-top: var(--wp-admin--admin-bar--height);
}
#wpadminbar * {
height: auto;
width: auto;
margin: 0;
padding: 0;
position: static;
text-shadow: none;
text-transform: none;
letter-spacing: normal;
font-size: 13px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-style: normal;
line-height: 2.46153846;
border-radius: 0;
box-sizing: content-box;
transition: none;
-webkit-font-smoothing: subpixel-antialiased; /* Prevent Safari from switching to standard antialiasing on hover */
-moz-osx-font-smoothing: auto; /* Prevent Firefox from inheriting from themes that use other values */
}
.rtl #wpadminbar * {
font-family: Tahoma, sans-serif;
}
html:lang(he-il) .rtl #wpadminbar * {
font-family: Arial, sans-serif;
}
#wpadminbar .ab-empty-item {
cursor: default;
}
#wpadminbar .ab-empty-item,
#wpadminbar a.ab-item,
#wpadminbar > #wp-toolbar span.ab-label,
#wpadminbar > #wp-toolbar span.noticon {
color: #f0f0f1;
}
#wpadminbar #wp-admin-bar-site-name a.ab-item,
#wpadminbar #wp-admin-bar-my-sites a.ab-item {
white-space: nowrap;
}
#wpadminbar ul li:before,
#wpadminbar ul li:after {
content: normal;
}
#wpadminbar a,
#wpadminbar a:hover,
#wpadminbar a img,
#wpadminbar a img:hover {
border: none;
text-decoration: none;
background: none;
box-shadow: none;
}
#wpadminbar a:focus,
#wpadminbar a:active,
#wpadminbar input[type="text"],
#wpadminbar input[type="password"],
#wpadminbar input[type="number"],
#wpadminbar input[type="search"],
#wpadminbar input[type="email"],
#wpadminbar input[type="url"],
#wpadminbar select,
#wpadminbar textarea,
#wpadminbar div {
box-shadow: none;
}
#wpadminbar a:focus {
/* Inherits transparent outline only visible in Windows High Contrast mode */
outline-offset: -1px;
}
#wpadminbar {
direction: rtl;
color: #c3c4c7;
font-size: 13px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
line-height: 2.46153846;
height: 32px;
position: fixed;
top: 0;
right: 0;
width: 100%;
min-width: 600px; /* match the min-width of the body in wp-admin/css/common.css */
z-index: 99999;
background: #1d2327;
/* Only visible in Windows High Contrast mode */
outline: 1px solid transparent;
}
#wpadminbar .ab-sub-wrapper,
#wpadminbar ul,
#wpadminbar ul li {
background: none;
clear: none;
list-style: none;
margin: 0;
padding: 0;
position: relative;
text-indent: 0;
z-index: 99999;
}
#wpadminbar ul#wp-admin-bar-root-default>li {
margin-left: 0;
}
#wpadminbar .quicklinks ul {
text-align: right;
}
#wpadminbar li {
float: right;
}
#wpadminbar .ab-empty-item {
outline: none;
}
#wpadminbar .quicklinks a,
#wpadminbar .quicklinks .ab-empty-item,
#wpadminbar .shortlink-input {
height: 32px;
display: block;
padding: 0 10px;
margin: 0;
}
#wpadminbar .quicklinks > ul > li > a {
padding: 0 7px 0 8px;
}
#wpadminbar .menupop .ab-sub-wrapper,
#wpadminbar .shortlink-input {
margin: 0;
padding: 0;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);
background: #2c3338;
display: none;
position: absolute;
float: none;
}
#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper {
min-width: 100%;
}
#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper {
left: 0;
right: auto;
}
#wpadminbar .ab-submenu {
padding: 6px 0;
}
#wpadminbar .selected .shortlink-input {
display: block;
}
#wpadminbar .quicklinks .menupop ul li {
float: none;
}
#wpadminbar .quicklinks .menupop ul li a strong {
font-weight: 600;
}
#wpadminbar .quicklinks .menupop ul li .ab-item,
#wpadminbar .quicklinks .menupop ul li a strong,
#wpadminbar .quicklinks .menupop.hover ul li .ab-item,
#wpadminbar.nojs .quicklinks .menupop:hover ul li .ab-item,
#wpadminbar .shortlink-input {
line-height: 2;
height: 26px;
white-space: nowrap;
min-width: 140px;
}
#wpadminbar .shortlink-input {
width: 200px;
}
#wpadminbar.nojs li:hover > .ab-sub-wrapper,
#wpadminbar li.hover > .ab-sub-wrapper {
display: block;
/* Only visible in Windows High Contrast mode */
outline: 1px solid transparent;
}
#wpadminbar .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .menupop li.hover > .ab-sub-wrapper {
margin-right: 100%;
margin-top: -32px;
}
#wpadminbar .ab-top-secondary .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .ab-top-secondary .menupop li.hover > .ab-sub-wrapper {
margin-right: 0;
right: inherit;
left: 100%;
}
#wpadminbar:not(.mobile) .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus,
#wpadminbar:not(.mobile) .ab-top-menu > li:hover > .ab-item,
#wpadminbar .ab-top-menu > li.hover > .ab-item {
background: #2c3338;
color: #72aee6;
}
#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label,
#wpadminbar > #wp-toolbar li.hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label {
color: #72aee6;
}
#wpadminbar > #wp-toolbar > #wp-admin-bar-root-default .ab-icon,
#wpadminbar .ab-icon,
#wpadminbar .ab-item:before,
.wp-admin-bar-arrow {
position: relative;
float: right;
font: normal 20px/1 dashicons;
speak: never;
padding: 4px 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-image: none !important;
margin-left: 6px;
}
#wpadminbar .ab-icon:before,
#wpadminbar .ab-item:before,
#wpadminbar #adminbarsearch:before {
color: #a7aaad;
color: rgba(240, 246, 252, 0.6);
}
#wpadminbar .ab-icon:before,
#wpadminbar .ab-item:before,
#wpadminbar #adminbarsearch:before {
position: relative;
transition: color .1s ease-in-out;
}
#wpadminbar .ab-label {
display: inline-block;
height: 32px;
}
#wpadminbar .ab-submenu .ab-item {
color: #c3c4c7;
color: rgba(240, 246, 252, 0.7);
}
#wpadminbar .quicklinks .menupop ul li a,
#wpadminbar .quicklinks .menupop ul li a strong,
#wpadminbar .quicklinks .menupop.hover ul li a,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
color: #c3c4c7;
color: rgba(240, 246, 252, 0.7);
}
#wpadminbar .quicklinks .menupop ul li a:hover,
#wpadminbar .quicklinks .menupop ul li a:focus,
#wpadminbar .quicklinks .menupop ul li a:hover strong,
#wpadminbar .quicklinks .menupop ul li a:focus strong,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a,
#wpadminbar .quicklinks .menupop.hover ul li a:hover,
#wpadminbar .quicklinks .menupop.hover ul li a:focus,
#wpadminbar .quicklinks .menupop.hover ul li div[tabindex]:hover,
#wpadminbar .quicklinks .menupop.hover ul li div[tabindex]:focus,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,
#wpadminbar li:hover .ab-icon:before,
#wpadminbar li:hover .ab-item:before,
#wpadminbar li a:focus .ab-icon:before,
#wpadminbar li .ab-item:focus:before,
#wpadminbar li .ab-item:focus .ab-icon:before,
#wpadminbar li.hover .ab-icon:before,
#wpadminbar li.hover .ab-item:before,
#wpadminbar li:hover #adminbarsearch:before,
#wpadminbar li #adminbarsearch.adminbar-focused:before {
color: #72aee6;
}
#wpadminbar.mobile .quicklinks .ab-icon:before,
#wpadminbar.mobile .quicklinks .ab-item:before {
color: #c3c4c7;
}
#wpadminbar.mobile .quicklinks .hover .ab-icon:before,
#wpadminbar.mobile .quicklinks .hover .ab-item:before {
color: #72aee6;
}
#wpadminbar .menupop .menupop > .ab-item .wp-admin-bar-arrow:before,
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item:before {
position: absolute;
font: normal 17px/1 dashicons;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#wpadminbar .menupop .menupop > .ab-item {
display: block;
padding-left: 2em;
}
#wpadminbar .menupop .menupop > .ab-item .wp-admin-bar-arrow:before {
top: 1px;
left: 10px;
padding: 4px 0;
content: "\f141";
color: inherit;
}
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item {
padding-right: 2em;
padding-left: 1em;
}
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item .wp-admin-bar-arrow:before {
top: 1px;
right: 6px;
content: "\f139";
}
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary {
display: block;
position: relative;
left: auto;
margin: 0;
box-shadow: none;
}
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu {
background: #3c434a;
}
#wpadminbar .quicklinks .menupop .ab-sub-secondary > li > a:hover,
#wpadminbar .quicklinks .menupop .ab-sub-secondary > li .ab-item:focus a {
color: #72aee6;
}
#wpadminbar .quicklinks a span#ab-updates {
background: #f0f0f1;
color: #2c3338;
display: inline;
padding: 2px 5px;
font-size: 10px;
font-weight: 600;
border-radius: 10px;
}
#wpadminbar .quicklinks a:hover span#ab-updates {
background: #fff;
color: #000;
}
#wpadminbar .ab-top-secondary {
float: left;
}
#wpadminbar ul li:last-child,
#wpadminbar ul li:last-child .ab-item {
box-shadow: none;
}
/**
* Recovery Mode
*/
#wpadminbar #wp-admin-bar-recovery-mode {
color: #fff;
background-color: #d63638;
}
#wpadminbar .ab-top-menu > #wp-admin-bar-recovery-mode.hover >.ab-item,
#wpadminbar.nojq .quicklinks .ab-top-menu > #wp-admin-bar-recovery-mode > .ab-item:focus,
#wpadminbar:not(.mobile) .ab-top-menu > #wp-admin-bar-recovery-mode:hover > .ab-item,
#wpadminbar:not(.mobile) .ab-top-menu > #wp-admin-bar-recovery-mode > .ab-item:focus {
color: #fff;
background-color: #d63638;
}
/**
* My Account
*/
#wp-admin-bar-my-account > ul {
min-width: 198px;
}
#wp-admin-bar-my-account:not(.with-avatar) > .ab-item {
display: inline-block;
}
#wp-admin-bar-my-account > .ab-item:before {
content: "\f110";
top: 2px;
float: left;
margin-right: 6px;
margin-left: 0;
}
#wp-admin-bar-my-account.with-avatar > .ab-item:before {
display: none;
content: none;
}
#wp-admin-bar-my-account.with-avatar > ul {
min-width: 270px;
}
#wpadminbar #wp-admin-bar-user-actions > li {
margin-right: 16px;
margin-left: 16px;
}
#wpadminbar #wp-admin-bar-user-actions.ab-submenu {
padding: 6px 0 12px;
}
#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions > li {
margin-right: 88px;
}
#wpadminbar #wp-admin-bar-user-info {
margin-top: 6px;
margin-bottom: 15px;
height: auto;
background: none;
}
#wp-admin-bar-user-info .avatar {
position: absolute;
right: -72px;
top: 4px;
width: 64px;
height: 64px;
}
#wpadminbar #wp-admin-bar-user-info a {
background: none;
height: auto;
}
#wpadminbar #wp-admin-bar-user-info span {
background: none;
padding: 0;
height: 18px;
}
#wpadminbar #wp-admin-bar-user-info .display-name,
#wpadminbar #wp-admin-bar-user-info .username {
display: block;
}
#wpadminbar #wp-admin-bar-user-info .username {
color: #a7aaad;
font-size: 11px;
}
#wpadminbar #wp-admin-bar-my-account.with-avatar > .ab-empty-item img,
#wpadminbar #wp-admin-bar-my-account.with-avatar > a img {
width: auto;
height: 16px;
padding: 0;
border: 1px solid #8c8f94;
background: #f0f0f1;
line-height: 1.84615384;
vertical-align: middle;
margin: -4px 6px 0 0;
float: none;
display: inline;
}
/**
* WP Logo
*/
#wpadminbar #wp-admin-bar-wp-logo > .ab-item .ab-icon {
width: 15px;
height: 20px;
margin-left: 0;
padding: 6px 0 5px;
}
#wpadminbar #wp-admin-bar-wp-logo > .ab-item {
padding: 0 7px;
}
#wpadminbar #wp-admin-bar-wp-logo > .ab-item .ab-icon:before {
content: "\f120";
top: 2px;
}
/*
* My Sites & Site Title
*/
#wpadminbar .quicklinks li .blavatar {
display: inline-block;
vertical-align: middle;
font: normal 16px/1 dashicons !important;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #f0f0f1;
}
#wpadminbar .quicklinks li a:hover .blavatar,
#wpadminbar .quicklinks li a:focus .blavatar,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a .blavatar {
color: #72aee6;
}
#wpadminbar .quicklinks li img.blavatar,
#wpadminbar .quicklinks li div.blavatar:before {
height: 16px;
width: 16px;
margin: 0 -2px 2px 8px;
}
#wpadminbar .quicklinks li div.blavatar:before {
content: "\f120";
display: inline-block;
}
#wpadminbar #wp-admin-bar-appearance {
margin-top: -12px;
}
#wpadminbar #wp-admin-bar-my-sites > .ab-item:before,
#wpadminbar #wp-admin-bar-site-name > .ab-item:before {
content: "\f541";
top: 2px;
}
#wpadminbar #wp-admin-bar-site-editor > .ab-item:before {
content: "\f100";
top: 2px;
}
#wpadminbar #wp-admin-bar-customize > .ab-item:before {
content: "\f540";
top: 2px;
}
#wpadminbar #wp-admin-bar-edit > .ab-item:before {
content: "\f464";
top: 2px;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item:before {
content: "\f226";
}
.wp-admin #wpadminbar #wp-admin-bar-site-name > .ab-item:before {
content: "\f102";
}
/**
* Comments
*/
#wpadminbar #wp-admin-bar-comments .ab-icon {
margin-left: 6px;
}
#wpadminbar #wp-admin-bar-comments .ab-icon:before {
content: "\f101";
top: 3px;
}
#wpadminbar #wp-admin-bar-comments .count-0 {
opacity: .5;
}
/**
* New Content
*/
#wpadminbar #wp-admin-bar-new-content .ab-icon:before {
content: "\f132";
top: 4px;
}
/**
* Updates
*/
#wpadminbar #wp-admin-bar-updates .ab-icon:before {
content: "\f463";
top: 2px;
}
#wpadminbar #wp-admin-bar-updates.spin .ab-icon:before {
display: inline-block;
animation: rotation 2s infinite linear;
}
@media (prefers-reduced-motion: reduce) {
#wpadminbar #wp-admin-bar-updates.spin .ab-icon:before {
animation: none;
}
}
/**
* Search
*/
#wpadminbar #wp-admin-bar-search .ab-item {
padding: 0;
background: transparent;
}
#wpadminbar #adminbarsearch {
position: relative;
height: 32px;
padding: 0 2px;
z-index: 1;
}
#wpadminbar #adminbarsearch:before {
position: absolute;
top: 6px;
right: 5px;
z-index: 20;
font: normal 20px/1 dashicons !important;
content: "\f179";
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* The admin bar search field needs to reset many styles that might be inherited from the active Theme CSS. See ticket #40313. */
#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input {
display: inline-block;
float: none;
position: relative;
z-index: 30;
font-size: 13px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
line-height: 1.84615384;
text-indent: 0;
height: 24px;
width: 24px;
max-width: none;
padding: 0 24px 0 3px;
margin: 0;
color: #c3c4c7;
background-color: rgba(255, 255, 255, 0);
border: none;
outline: none;
cursor: pointer;
box-shadow: none;
box-sizing: border-box;
transition-duration: 400ms;
transition-property: width, background;
transition-timing-function: ease;
}
#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus {
z-index: 10;
color: #000;
width: 200px;
background-color: rgba(255, 255, 255, 0.9);
cursor: text;
border: 0;
}
#wpadminbar #adminbarsearch .adminbar-button {
display: none;
}
/**
* Customize support classes
*/
.no-customize-support .hide-if-no-customize,
.customize-support .hide-if-customize,
.no-customize-support #wpadminbar .hide-if-no-customize,
.no-customize-support.wp-core-ui .hide-if-no-customize,
.no-customize-support .wp-core-ui .hide-if-no-customize,
.customize-support #wpadminbar .hide-if-customize,
.customize-support.wp-core-ui .hide-if-customize,
.customize-support .wp-core-ui .hide-if-customize {
display: none;
}
/* Skip link */
#wpadminbar .screen-reader-text,
#wpadminbar .screen-reader-text span {
border: 0;
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
#wpadminbar .screen-reader-shortcut {
position: absolute;
top: -1000em;
right: 6px;
height: auto;
width: auto;
display: block;
font-size: 14px;
font-weight: 600;
padding: 15px 23px 14px;
background: #f0f0f1;
color: #2271b1;
z-index: 100000;
line-height: normal;
text-decoration: none;
}
#wpadminbar .screen-reader-shortcut:focus {
top: 7px;
background: #f0f0f1;
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
}
@media screen and (max-width: 782px) {
html {
--wp-admin--admin-bar--height: 46px;
}
/* Toolbar Touchification*/
html #wpadminbar {
height: 46px;
min-width: 240px; /* match the min-width of the body in wp-admin/css/common.css */
}
#wpadminbar * {
font-size: 14px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
line-height: 2.28571428;
}
#wpadminbar .quicklinks > ul > li > a,
#wpadminbar .quicklinks .ab-empty-item {
padding: 0;
height: 46px;
line-height: 3.28571428;
width: auto;
}
#wpadminbar .ab-icon {
font: 40px/1 dashicons !important;
margin: 0;
padding: 0;
width: 52px;
height: 46px;
text-align: center;
}
#wpadminbar .ab-icon:before {
text-align: center;
}
#wpadminbar .ab-submenu {
padding: 0;
}
#wpadminbar #wp-admin-bar-site-name a.ab-item,
#wpadminbar #wp-admin-bar-my-sites a.ab-item,
#wpadminbar #wp-admin-bar-my-account a.ab-item {
text-overflow: clip;
}
#wpadminbar .quicklinks .menupop ul li .ab-item,
#wpadminbar .quicklinks .menupop ul li a strong,
#wpadminbar .quicklinks .menupop.hover ul li .ab-item,
#wpadminbar.nojs .quicklinks .menupop:hover ul li .ab-item,
#wpadminbar .shortlink-input {
line-height: 1.6;
}
#wpadminbar .ab-label {
border: 0;
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
#wpadminbar .menupop li:hover > .ab-sub-wrapper,
#wpadminbar .menupop li.hover > .ab-sub-wrapper {
margin-top: -46px;
}
#wpadminbar .ab-top-menu .menupop .ab-sub-wrapper .menupop > .ab-item {
padding-left: 30px;
}
#wpadminbar .menupop .menupop > .ab-item:before {
top: 10px;
left: 6px;
}
#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper .ab-item {
font-size: 16px;
padding: 8px 16px;
}
#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper a:empty {
display: none;
}
/* WP logo */
#wpadminbar #wp-admin-bar-wp-logo > .ab-item {
padding: 0;
}
#wpadminbar #wp-admin-bar-wp-logo > .ab-item .ab-icon {
padding: 0;
width: 52px;
height: 46px;
text-align: center;
vertical-align: top;
}
#wpadminbar #wp-admin-bar-wp-logo > .ab-item .ab-icon:before {
font: 28px/1 dashicons !important;
top: -3px;
}
#wpadminbar .ab-icon,
#wpadminbar .ab-item:before {
padding: 0;
}
/* My Sites and "Site Title" menu */
#wpadminbar #wp-admin-bar-my-sites > .ab-item,
#wpadminbar #wp-admin-bar-site-name > .ab-item,
#wpadminbar #wp-admin-bar-site-editor > .ab-item,
#wpadminbar #wp-admin-bar-customize > .ab-item,
#wpadminbar #wp-admin-bar-edit > .ab-item,
#wpadminbar #wp-admin-bar-my-account > .ab-item {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
width: 52px;
padding: 0;
color: #a7aaad; /* @todo not needed? this text is hidden */
position: relative;
}
#wpadminbar > #wp-toolbar > #wp-admin-bar-root-default .ab-icon,
#wpadminbar .ab-icon,
#wpadminbar .ab-item:before {
padding: 0;
margin-left: 0;
}
#wpadminbar #wp-admin-bar-edit > .ab-item:before,
#wpadminbar #wp-admin-bar-my-sites > .ab-item:before,
#wpadminbar #wp-admin-bar-site-name > .ab-item:before,
#wpadminbar #wp-admin-bar-site-editor > .ab-item:before,
#wpadminbar #wp-admin-bar-customize > .ab-item:before,
#wpadminbar #wp-admin-bar-my-account > .ab-item:before {
display: block;
text-indent: 0;
font: normal 32px/1 dashicons;
speak: never;
top: 7px;
width: 52px;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#wpadminbar #wp-admin-bar-appearance {
margin-top: 0;
}
#wpadminbar .quicklinks li .blavatar:before {
display: none;
}
/* Search */
#wpadminbar #wp-admin-bar-search {
display: none;
}
/* New Content */
#wpadminbar #wp-admin-bar-new-content .ab-icon:before {
top: 0;
line-height: 1.26;
height: 46px !important;
text-align: center;
width: 52px;
display: block;
}
/* Updates */
#wpadminbar #wp-admin-bar-updates {
text-align: center;
}
#wpadminbar #wp-admin-bar-updates .ab-icon:before {
top: 3px;
}
/* Comments */
#wpadminbar #wp-admin-bar-comments .ab-icon {
margin: 0;
}
#wpadminbar #wp-admin-bar-comments .ab-icon:before {
display: block;
font-size: 34px;
height: 46px;
line-height: 1.38235294;
top: 0;
}
/* My Account */
#wpadminbar #wp-admin-bar-my-account > a {
position: relative;
white-space: nowrap;
text-indent: 150%; /* More than 100% indention is needed since this element has padding */
width: 28px;
padding: 0 10px;
overflow: hidden; /* Prevent link text from forcing horizontal scrolling on mobile */
}
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
position: absolute;
top: 13px;
left: 10px;
width: 26px;
height: 26px;
}
#wpadminbar #wp-admin-bar-user-actions.ab-submenu {
padding: 0;
}
#wpadminbar #wp-admin-bar-user-actions.ab-submenu img.avatar {
display: none;
}
#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions > li {
margin: 0;
}
#wpadminbar #wp-admin-bar-user-info .display-name {
height: auto;
font-size: 16px;
line-height: 1.5;
color: #f0f0f1;
}
#wpadminbar #wp-admin-bar-user-info a {
padding-top: 4px;
}
#wpadminbar #wp-admin-bar-user-info .username {
line-height: 0.8 !important;
margin-bottom: -2px;
}
/* Show only default top level items */
#wp-toolbar > ul > li {
display: none;
}
#wpadminbar li#wp-admin-bar-menu-toggle,
#wpadminbar li#wp-admin-bar-wp-logo,
#wpadminbar li#wp-admin-bar-my-sites,
#wpadminbar li#wp-admin-bar-updates,
#wpadminbar li#wp-admin-bar-site-name,
#wpadminbar li#wp-admin-bar-site-editor,
#wpadminbar li#wp-admin-bar-customize,
#wpadminbar li#wp-admin-bar-new-content,
#wpadminbar li#wp-admin-bar-edit,
#wpadminbar li#wp-admin-bar-comments,
#wpadminbar li#wp-admin-bar-my-account {
display: block;
}
/* Allow dropdown list items to appear normally */
#wpadminbar li:hover ul li,
#wpadminbar li.hover ul li,
#wpadminbar li:hover ul li:hover ul li {
display: list-item;
}
/* Override default min-width so dropdown lists aren't stretched
to 100% viewport width at responsive sizes. */
#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper {
min-width: fit-content;
}
#wpadminbar ul#wp-admin-bar-root-default > li {
margin-left: 0;
}
/* Experimental fix for touch toolbar dropdown positioning */
#wpadminbar .ab-top-menu,
#wpadminbar .ab-top-secondary,
#wpadminbar #wp-admin-bar-wp-logo,
#wpadminbar #wp-admin-bar-my-sites,
#wpadminbar #wp-admin-bar-site-name,
#wpadminbar #wp-admin-bar-updates,
#wpadminbar #wp-admin-bar-comments,
#wpadminbar #wp-admin-bar-new-content,
#wpadminbar #wp-admin-bar-edit,
#wpadminbar #wp-admin-bar-my-account {
position: static;
}
.network-admin #wpadminbar ul#wp-admin-bar-top-secondary > li#wp-admin-bar-my-account {
margin-left: 0;
}
/* Realign arrows on taller responsive submenus */
#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item:before {
top: 10px;
right: 0;
}
}
/* Smartphone */
@media screen and (max-width: 600px) {
#wpadminbar {
position: absolute;
}
#wp-responsive-overlay {
position: fixed;
top: 0;
right: 0;
width: 100%;
height: 100%;
z-index: 400;
}
#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper {
width: 100%;
right: 0;
}
#wpadminbar .menupop .menupop > .ab-item:before {
display: none;
}
#wpadminbar #wp-admin-bar-wp-logo.menupop .ab-sub-wrapper {
margin-right: 0;
}
#wpadminbar .ab-top-menu > .menupop li > .ab-sub-wrapper {
margin: 0;
width: 100%;
top: auto;
right: auto;
position: relative;
}
#wpadminbar .ab-top-menu > .menupop li > .ab-sub-wrapper .ab-item {
font-size: 16px;
padding: 6px 30px 19px 15px;
}
#wpadminbar li:hover ul li ul li {
display: list-item;
}
#wpadminbar li#wp-admin-bar-wp-logo,
#wpadminbar li#wp-admin-bar-updates {
display: none;
}
/* Make submenus full-width at this size */
#wpadminbar .ab-top-menu > .menupop li > .ab-sub-wrapper {
position: static;
box-shadow: none;
}
}
/* Very narrow screens */
@media screen and (max-width: 400px) {
#wpadminbar li#wp-admin-bar-comments {
display: none;
}
}
/*! This file is auto-generated */
#wp-auth-check-wrap.hidden{display:none}#wp-auth-check-wrap #wp-auth-check-bg{position:fixed;top:0;bottom:0;right:0;left:0;background:#000;opacity:.7;z-index:1000010}#wp-auth-check-wrap #wp-auth-check{position:fixed;right:50%;overflow:hidden;top:40px;bottom:20px;max-height:415px;width:380px;margin:0 -190px 0 0;padding:30px 0 0;background-color:#f0f0f1;z-index:1000011;box-shadow:0 3px 6px rgba(0,0,0,.3)}@media screen and (max-width:380px){#wp-auth-check-wrap #wp-auth-check{right:0;width:100%;margin:0}}#wp-auth-check-wrap.fallback #wp-auth-check{max-height:180px;overflow:auto}#wp-auth-check-wrap #wp-auth-check-form{height:100%;position:relative;overflow:auto;-webkit-overflow-scrolling:touch}#wp-auth-check-form.loading:before{content:"";display:block;width:20px;height:20px;position:absolute;right:50%;top:50%;margin:-10px -10px 0 0;background:url(../images/spinner.gif) no-repeat center;background-size:20px 20px;transform:translateZ(0)}@media print,(min-resolution:120dpi){#wp-auth-check-form.loading:before{background-image:url(../images/spinner-2x.gif)}}#wp-auth-check-wrap #wp-auth-check-form iframe{height:98%;width:100%}#wp-auth-check-wrap .wp-auth-check-close{position:absolute;top:5px;left:5px;height:22px;width:22px;color:#787c82;text-decoration:none;text-align:center}#wp-auth-check-wrap .wp-auth-check-close:before{content:"\f158";font:normal 20px/22px dashicons;speak:never;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale}#wp-auth-check-wrap .wp-auth-check-close:focus,#wp-auth-check-wrap .wp-auth-check-close:hover{color:#2271b1}#wp-auth-check-wrap .wp-auth-fallback-expired{outline:0}#wp-auth-check-wrap .wp-auth-fallback{font-size:14px;line-height:1.5;padding:0 25px;display:none}#wp-auth-check-wrap.fallback .wp-auth-check-close,#wp-auth-check-wrap.fallback .wp-auth-fallback{display:block}/*! This file is auto-generated */
/*------------------------------------------------------------------------------
TinyMCE and Quicklinks toolbars
------------------------------------------------------------------------------*/
/* TinyMCE widgets/containers */
.mce-tinymce {
box-shadow: none;
}
.mce-container,
.mce-container *,
.mce-widget,
.mce-widget * {
color: inherit;
font-family: inherit;
}
.mce-container .mce-monospace,
.mce-widget .mce-monospace {
font-family: Consolas, Monaco, monospace;
font-size: 13px;
line-height: 150%;
}
/* TinyMCE windows */
#mce-modal-block,
#mce-modal-block.mce-fade {
opacity: 0.7;
filter: alpha(opacity=70);
transition: none;
background: #000;
}
.mce-window {
border-radius: 0;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
-webkit-font-smoothing: subpixel-antialiased;
transition: none;
}
.mce-window .mce-container-body.mce-abs-layout {
overflow: visible;
}
.mce-window .mce-window-head {
background: #fff;
border-bottom: 1px solid #dcdcde;
padding: 0;
min-height: 36px;
}
.mce-window .mce-window-head .mce-title {
color: #3c434a;
font-size: 18px;
font-weight: 600;
line-height: 36px;
margin: 0;
padding: 0 16px 0 36px;
}
.mce-window .mce-window-head .mce-close,
.mce-window-head .mce-close .mce-i-remove {
color: transparent;
top: 0;
left: 0;
width: 36px;
height: 36px;
padding: 0;
line-height: 36px;
text-align: center;
}
.mce-window-head .mce-close .mce-i-remove:before {
font: normal 20px/36px dashicons;
text-align: center;
color: #646970;
width: 36px;
height: 36px;
display: block;
}
.mce-window-head .mce-close:hover .mce-i-remove:before,
.mce-window-head .mce-close:focus .mce-i-remove:before {
color: #135e96;
}
.mce-window-head .mce-close:focus .mce-i-remove,
div.mce-tab:focus {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
.mce-window .mce-window-head .mce-dragh {
width: calc( 100% - 36px );
}
.mce-window .mce-foot {
border-top: 1px solid #dcdcde;
}
.mce-textbox,
.mce-checkbox i.mce-i-checkbox,
#wp-link .query-results {
border: 1px solid #dcdcde;
border-radius: 0;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
transition: .05s all ease-in-out;
}
.mce-textbox:focus,
.mce-textbox.mce-focus,
.mce-checkbox:focus i.mce-i-checkbox,
#wp-link .query-results:focus {
border-color: #4f94d4;
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
.mce-window .mce-wp-help {
height: 360px;
width: 460px;
overflow: auto;
}
.mce-window .mce-wp-help * {
box-sizing: border-box;
}
.mce-window .mce-wp-help > .mce-container-body {
width: auto !important;
}
.mce-window .wp-editor-help {
padding: 10px 20px 0 10px;
}
.mce-window .wp-editor-help h2,
.mce-window .wp-editor-help p {
margin: 8px 0;
white-space: normal;
font-size: 14px;
font-weight: 400;
}
.mce-window .wp-editor-help table {
width: 100%;
margin-bottom: 20px;
}
.mce-window .wp-editor-help table.wp-help-single {
margin: 0 8px 20px;
}
.mce-window .wp-editor-help table.fixed {
table-layout: fixed;
}
.mce-window .wp-editor-help table.fixed th:nth-child(odd),
.mce-window .wp-editor-help table.fixed td:nth-child(odd) {
width: 12%;
}
.mce-window .wp-editor-help table.fixed th:nth-child(even),
.mce-window .wp-editor-help table.fixed td:nth-child(even) {
width: 38%;
}
.mce-window .wp-editor-help table.fixed th:nth-child(odd) {
padding: 5px 0 0;
}
.mce-window .wp-editor-help td,
.mce-window .wp-editor-help th {
font-size: 13px;
padding: 5px;
vertical-align: middle;
word-wrap: break-word;
white-space: normal;
}
.mce-window .wp-editor-help th {
font-weight: 600;
padding-bottom: 0;
}
.mce-window .wp-editor-help kbd {
font-family: monospace;
padding: 2px 7px 3px;
font-weight: 600;
margin: 0;
background: #f0f0f1;
background: rgba(0, 0, 0, 0.08);
}
.mce-window .wp-help-th-center td:nth-child(odd),
.mce-window .wp-help-th-center th:nth-child(odd) {
text-align: center;
}
/* TinyMCE menus */
.mce-menu,
.mce-floatpanel.mce-popover {
border-color: rgba(0, 0, 0, 0.15);
border-radius: 0;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);
}
.mce-menu,
.mce-floatpanel.mce-popover.mce-bottom {
margin-top: 2px;
}
.mce-floatpanel .mce-arrow {
display: none;
}
.mce-menu .mce-container-body {
min-width: 160px;
}
.mce-menu-item {
border: none;
margin-bottom: 2px;
padding: 6px 12px 6px 15px;
}
.mce-menu-has-icons i.mce-ico {
line-height: 20px;
}
/* TinyMCE panel */
div.mce-panel {
border: 0;
background: #fff;
}
.mce-panel.mce-menu {
border: 1px solid #dcdcde;
}
div.mce-tab {
line-height: 13px;
}
/* TinyMCE toolbars */
div.mce-toolbar-grp {
border-bottom: 1px solid #dcdcde;
background: #f6f7f7;
padding: 0;
position: relative;
}
div.mce-inline-toolbar-grp {
border: 1px solid #a7aaad;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
box-sizing: border-box;
margin-bottom: 8px;
position: absolute;
-webkit-user-select: none;
user-select: none;
max-width: 98%;
z-index: 100100; /* Same as the other TinyMCE "panels" */
}
div.mce-inline-toolbar-grp > div.mce-stack-layout {
padding: 1px;
}
div.mce-inline-toolbar-grp.mce-arrow-up {
margin-bottom: 0;
margin-top: 8px;
}
div.mce-inline-toolbar-grp:before,
div.mce-inline-toolbar-grp:after {
position: absolute;
right: 50%;
display: block;
width: 0;
height: 0;
border-style: solid;
border-color: transparent;
content: "";
}
div.mce-inline-toolbar-grp.mce-arrow-up:before {
top: -9px;
border-bottom-color: #a7aaad;
border-width: 0 9px 9px;
margin-right: -9px;
}
div.mce-inline-toolbar-grp.mce-arrow-down:before {
bottom: -9px;
border-top-color: #a7aaad;
border-width: 9px 9px 0;
margin-right: -9px;
}
div.mce-inline-toolbar-grp.mce-arrow-up:after {
top: -8px;
border-bottom-color: #f6f7f7;
border-width: 0 8px 8px;
margin-right: -8px;
}
div.mce-inline-toolbar-grp.mce-arrow-down:after {
bottom: -8px;
border-top-color: #f6f7f7;
border-width: 8px 8px 0;
margin-right: -8px;
}
div.mce-inline-toolbar-grp.mce-arrow-left:before,
div.mce-inline-toolbar-grp.mce-arrow-left:after {
margin: 0;
}
div.mce-inline-toolbar-grp.mce-arrow-left:before {
right: 20px;
}
div.mce-inline-toolbar-grp.mce-arrow-left:after {
right: 21px;
}
div.mce-inline-toolbar-grp.mce-arrow-right:before,
div.mce-inline-toolbar-grp.mce-arrow-right:after {
right: auto;
margin: 0;
}
div.mce-inline-toolbar-grp.mce-arrow-right:before {
left: 20px;
}
div.mce-inline-toolbar-grp.mce-arrow-right:after {
left: 21px;
}
div.mce-inline-toolbar-grp.mce-arrow-full {
left: 0;
}
div.mce-inline-toolbar-grp.mce-arrow-full > div {
width: 100%;
overflow-x: auto;
}
div.mce-toolbar-grp > div {
padding: 3px;
}
.has-dfw div.mce-toolbar-grp .mce-toolbar.mce-first {
padding-left: 32px;
}
.mce-toolbar .mce-btn-group {
margin: 0;
}
/* Classic block hide/show toolbars */
.block-library-classic__toolbar .mce-toolbar-grp .mce-toolbar:not(:first-child) {
display: none;
}
.block-library-classic__toolbar.has-advanced-toolbar .mce-toolbar-grp .mce-toolbar {
display: block;
}
div.mce-statusbar {
border-top: 1px solid #dcdcde;
}
div.mce-path {
padding: 2px 10px;
margin: 0;
}
.mce-path,
.mce-path-item,
.mce-path .mce-divider {
font-size: 12px;
}
.mce-toolbar .mce-btn,
.qt-dfw {
border-color: transparent;
background: transparent;
box-shadow: none;
text-shadow: none;
cursor: pointer;
}
.mce-btn .mce-txt {
direction: inherit;
text-align: inherit;
}
.mce-toolbar .mce-btn-group .mce-btn,
.qt-dfw {
border: 1px solid transparent;
margin: 2px;
border-radius: 2px;
}
.mce-toolbar .mce-btn-group .mce-btn:hover,
.mce-toolbar .mce-btn-group .mce-btn:focus,
.qt-dfw:hover,
.qt-dfw:focus {
background: #f6f7f7;
color: #1d2327;
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-active,
.mce-toolbar .mce-btn-group .mce-btn:active,
.qt-dfw.active {
background: #f0f0f1;
border-color: #50575e;
}
.mce-btn.mce-active,
.mce-btn.mce-active button,
.mce-btn.mce-active:hover button,
.mce-btn.mce-active i,
.mce-btn.mce-active:hover i {
color: inherit;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-active:hover,
.mce-toolbar .mce-btn-group .mce-btn.mce-active:focus {
border-color: #1d2327;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-disabled:hover,
.mce-toolbar .mce-btn-group .mce-btn.mce-disabled:focus {
color: #a7aaad;
background: none;
border-color: #dcdcde;
text-shadow: 0 1px 0 #fff;
box-shadow: none;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-disabled:focus {
border-color: #50575e;
}
.mce-toolbar .mce-btn-group .mce-first,
.mce-toolbar .mce-btn-group .mce-last {
border-color: transparent;
}
.mce-toolbar .mce-btn button,
.qt-dfw {
padding: 2px 3px;
line-height: normal;
}
.mce-toolbar .mce-listbox button {
font-size: 13px;
line-height: 1.53846153;
padding-right: 6px;
padding-left: 20px;
}
.mce-toolbar .mce-btn i {
text-shadow: none;
}
.mce-toolbar .mce-btn-group > div {
white-space: normal;
}
.mce-toolbar .mce-colorbutton .mce-open {
border-left: 0;
}
.mce-toolbar .mce-colorbutton .mce-preview {
margin: 0;
padding: 0;
top: auto;
bottom: 2px;
right: 3px;
height: 3px;
width: 20px;
background: #50575e;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-primary {
min-width: 0;
background: #3582c4;
border-color: #2271b1 #135e96 #135e96;
box-shadow: 0 1px 0 #135e96;
color: #fff;
text-decoration: none;
text-shadow: none;
}
/* Compensate for the extra box shadow at the bottom of .mce-btn.mce-primary */
.mce-toolbar .mce-btn-group .mce-btn.mce-primary button {
padding: 2px 3px 1px;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-primary .mce-ico {
color: #fff;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-primary:hover,
.mce-toolbar .mce-btn-group .mce-btn.mce-primary:focus {
background: #4f94d4;
border-color: #135e96;
color: #fff;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-primary:focus {
box-shadow: 0 0 1px 1px #72aee6;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-primary:active {
background: #2271b1;
border-color: #135e96;
box-shadow: inset 0 2px 0 #135e96;
}
/* mce listbox */
.mce-toolbar .mce-btn-group .mce-btn.mce-listbox {
border-radius: 0;
direction: rtl;
background: #fff;
border: 1px solid #dcdcde;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-listbox:hover,
.mce-toolbar .mce-btn-group .mce-btn.mce-listbox:focus {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
.mce-panel .mce-btn i.mce-caret {
border-top: 6px solid #50575e;
margin-right: 2px;
margin-left: 2px;
}
.mce-listbox i.mce-caret {
left: 4px;
}
.mce-panel .mce-btn:hover i.mce-caret,
.mce-panel .mce-btn:focus i.mce-caret {
border-top-color: #1d2327;
}
.mce-panel .mce-active i.mce-caret {
border-top: 0;
border-bottom: 6px solid #1d2327;
margin-top: 7px;
}
.mce-listbox.mce-active i.mce-caret {
margin-top: -3px;
}
.mce-toolbar .mce-splitbtn:hover .mce-open {
border-left-color: transparent;
}
.mce-toolbar .mce-splitbtn .mce-open.mce-active {
background: transparent;
outline: none;
}
.mce-menu .mce-menu-item:hover,
.mce-menu .mce-menu-item.mce-selected,
.mce-menu .mce-menu-item:focus,
.mce-menu .mce-menu-item.mce-active.mce-menu-item-normal,
.mce-menu .mce-menu-item.mce-active.mce-menu-item-preview {
background: #2271b1; /* See color scheme. */
color: #fff;
}
.mce-menu .mce-menu-item:hover .mce-caret,
.mce-menu .mce-menu-item:focus .mce-caret,
.mce-menu .mce-menu-item.mce-selected .mce-caret {
border-right-color: #fff;
}
/* rtl:ignore */
.rtl .mce-menu .mce-menu-item:hover .mce-caret,
.rtl .mce-menu .mce-menu-item:focus .mce-caret,
.rtl .mce-menu .mce-menu-item.mce-selected .mce-caret {
border-left-color: inherit;
border-right-color: #fff;
}
.mce-menu .mce-menu-item:hover .mce-text,
.mce-menu .mce-menu-item:focus .mce-text,
.mce-menu .mce-menu-item:hover .mce-ico,
.mce-menu .mce-menu-item:focus .mce-ico,
.mce-menu .mce-menu-item.mce-selected .mce-text,
.mce-menu .mce-menu-item.mce-selected .mce-ico,
.mce-menu .mce-menu-item:hover .mce-menu-shortcut,
.mce-menu .mce-menu-item:focus .mce-menu-shortcut,
.mce-menu .mce-menu-item.mce-active .mce-menu-shortcut,
.mce-menu .mce-menu-item.mce-disabled:hover .mce-text,
.mce-menu .mce-menu-item.mce-disabled:hover .mce-ico {
color: inherit;
}
.mce-menu .mce-menu-item.mce-disabled {
cursor: default;
}
.mce-menu .mce-menu-item.mce-disabled:hover {
background: #c3c4c7;
}
/* Menubar */
div.mce-menubar {
border-color: #dcdcde;
background: #fff;
border-width: 0 0 1px;
}
.mce-menubar .mce-menubtn:hover,
.mce-menubar .mce-menubtn.mce-active,
.mce-menubar .mce-menubtn:focus {
border-color: transparent;
background: transparent;
}
.mce-menubar .mce-menubtn:focus {
color: #043959;
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
div.mce-menu .mce-menu-item-sep,
.mce-menu-item-sep:hover {
border-bottom: 1px solid #dcdcde;
height: 0;
margin: 5px 0;
}
.mce-menubtn span {
margin-left: 0;
padding-right: 3px;
}
.mce-menu-has-icons i.mce-ico:before {
margin-right: -2px;
}
/* Keyboard shortcuts position */
.mce-menu.mce-menu-align .mce-menu-item-normal {
position: relative;
}
.mce-menu.mce-menu-align .mce-menu-shortcut {
bottom: 0.6em;
font-size: 0.9em;
}
/* Buttons in modals */
.mce-primary button,
.mce-primary button i {
text-align: center;
color: #fff;
text-shadow: none;
padding: 0;
line-height: 1.85714285;
}
.mce-window .mce-btn {
color: #50575e;
background: #f6f7f7;
text-decoration: none;
font-size: 13px;
line-height: 26px;
height: 28px;
margin: 0;
padding: 0;
cursor: pointer;
border: 1px solid #c3c4c7;
-webkit-appearance: none;
border-radius: 3px;
white-space: nowrap;
box-shadow: 0 1px 0 #c3c4c7;
}
/* Remove the dotted border on :focus and the extra padding in Firefox */
.mce-window .mce-btn::-moz-focus-inner {
border-width: 0;
border-style: none;
padding: 0;
}
.mce-window .mce-btn:hover,
.mce-window .mce-btn:focus {
background: #f6f7f7;
border-color: #8c8f94;
color: #1d2327;
}
.mce-window .mce-btn:focus {
border-color: #4f94d4;
box-shadow: 0 0 3px rgba(34, 113, 177, 0.8);
}
.mce-window .mce-btn:active {
background: #f0f0f1;
border-color: #8c8f94;
box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
transform: translateY(1px);
}
.mce-window .mce-btn.mce-disabled {
color: #a7aaad !important;
border-color: #dcdcde !important;
background: #f6f7f7 !important;
box-shadow: none !important;
text-shadow: 0 1px 0 #fff !important;
cursor: default;
transform: none !important;
}
.mce-window .mce-btn.mce-primary {
background: #3582c4;
border-color: #2271b1 #135e96 #135e96;
box-shadow: 0 1px 0 #135e96;
color: #fff;
text-decoration: none;
text-shadow: 0 -1px 1px #135e96,
-1px 0 1px #135e96,
0 1px 1px #135e96,
1px 0 1px #135e96;
}
.mce-window .mce-btn.mce-primary:hover,
.mce-window .mce-btn.mce-primary:focus {
background: #4f94d4;
border-color: #135e96;
color: #fff;
}
.mce-window .mce-btn.mce-primary:focus {
box-shadow: 0 1px 0 #2271b1,
0 0 2px 1px #72aee6;
}
.mce-window .mce-btn.mce-primary:active {
background: #2271b1;
border-color: #135e96;
box-shadow: inset 0 2px 0 #135e96;
vertical-align: top;
}
.mce-window .mce-btn.mce-primary.mce-disabled {
color: #9ec2e6 !important;
background: #4f94d4 !important;
border-color: #3582c4 !important;
box-shadow: none !important;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.1) !important;
cursor: default;
}
.mce-menubtn.mce-fixed-width span {
overflow-x: hidden;
text-overflow: ellipsis;
width: 82px;
}
/* Charmap modal */
.mce-charmap {
margin: 3px;
}
.mce-charmap td {
padding: 0;
border-color: #dcdcde;
cursor: pointer;
}
.mce-charmap td:hover {
background: #f6f7f7;
}
.mce-charmap td div {
width: 18px;
height: 22px;
line-height: 1.57142857;
}
/* TinyMCE tooltips */
.mce-tooltip {
margin-top: 2px;
}
.mce-tooltip-inner {
border-radius: 3px;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);
color: #fff;
font-size: 12px;
}
/* TinyMCE icons */
.mce-ico {
font-family: tinymce, Arial;
}
.mce-btn-small .mce-ico {
font-family: tinymce-small, Arial;
}
.mce-toolbar .mce-ico {
color: #50575e;
line-height: 1;
width: 20px;
height: 20px;
text-align: center;
text-shadow: none;
margin: 0;
padding: 0;
}
.qt-dfw {
color: #50575e;
line-height: 1;
width: 28px;
height: 26px;
text-align: center;
text-shadow: none;
}
.mce-toolbar .mce-btn .mce-open {
line-height: 20px;
}
.mce-toolbar .mce-btn:hover .mce-open,
.mce-toolbar .mce-btn:focus .mce-open,
.mce-toolbar .mce-btn.mce-active .mce-open {
border-right-color: #1d2327;
}
div.mce-notification {
right: 10% !important;
left: 10%;
}
.mce-notification button.mce-close {
left: 6px;
top: 3px;
font-weight: 400;
color: #50575e;
}
.mce-notification button.mce-close:hover,
.mce-notification button.mce-close:focus {
color: #000;
}
i.mce-i-bold,
i.mce-i-italic,
i.mce-i-bullist,
i.mce-i-numlist,
i.mce-i-blockquote,
i.mce-i-alignleft,
i.mce-i-aligncenter,
i.mce-i-alignright,
i.mce-i-link,
i.mce-i-unlink,
i.mce-i-wp_more,
i.mce-i-strikethrough,
i.mce-i-spellchecker,
i.mce-i-fullscreen,
i.mce-i-wp_fullscreen,
i.mce-i-dfw,
i.mce-i-wp_adv,
i.mce-i-underline,
i.mce-i-alignjustify,
i.mce-i-forecolor,
i.mce-i-backcolor,
i.mce-i-pastetext,
i.mce-i-pasteword,
i.mce-i-removeformat,
i.mce-i-charmap,
i.mce-i-outdent,
i.mce-i-indent,
i.mce-i-undo,
i.mce-i-redo,
i.mce-i-help,
i.mce-i-wp_help,
i.mce-i-wp-media-library,
i.mce-i-ltr,
i.mce-i-wp_page,
i.mce-i-hr,
i.mce-i-wp_code,
i.mce-i-dashicon,
i.mce-i-remove {
font: normal 20px/1 dashicons;
padding: 0;
vertical-align: top;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin-right: -2px;
padding-left: 2px;
}
.qt-dfw {
font: normal 20px/1 dashicons;
vertical-align: top;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
i.mce-i-bold:before {
content: "\f200";
}
i.mce-i-italic:before {
content: "\f201";
}
i.mce-i-bullist:before {
content: "\f203";
}
i.mce-i-numlist:before {
content: "\f204";
}
i.mce-i-blockquote:before {
content: "\f205";
}
i.mce-i-alignleft:before {
content: "\f206";
}
i.mce-i-aligncenter:before {
content: "\f207";
}
i.mce-i-alignright:before {
content: "\f208";
}
i.mce-i-link:before {
content: "\f103";
}
i.mce-i-unlink:before {
content: "\f225";
}
i.mce-i-wp_more:before {
content: "\f209";
}
i.mce-i-strikethrough:before {
content: "\f224";
}
i.mce-i-spellchecker:before {
content: "\f210";
}
i.mce-i-fullscreen:before,
i.mce-i-wp_fullscreen:before,
i.mce-i-dfw:before,
.qt-dfw:before {
content: "\f211";
}
i.mce-i-wp_adv:before {
content: "\f212";
}
i.mce-i-underline:before {
content: "\f213";
}
i.mce-i-alignjustify:before {
content: "\f214";
}
i.mce-i-forecolor:before,
i.mce-i-backcolor:before {
content: "\f215";
}
i.mce-i-pastetext:before {
content: "\f217";
}
i.mce-i-removeformat:before {
content: "\f218";
}
i.mce-i-charmap:before {
content: "\f220";
}
i.mce-i-outdent:before {
content: "\f221";
}
i.mce-i-indent:before {
content: "\f222";
}
i.mce-i-undo:before {
content: "\f171";
}
i.mce-i-redo:before {
content: "\f172";
}
i.mce-i-help:before,
i.mce-i-wp_help:before {
content: "\f223";
}
i.mce-i-wp-media-library:before {
content: "\f104";
}
i.mce-i-ltr:before {
content: "\f320";
}
i.mce-i-wp_page:before {
content: "\f105";
}
i.mce-i-hr:before {
content: "\f460";
}
i.mce-i-remove:before {
content: "\f158";
}
i.mce-i-wp_code:before {
content: "\f475";
}
/* RTL button icons */
.rtl i.mce-i-outdent:before {
content: "\f222";
}
.rtl i.mce-i-indent:before {
content: "\f221";
}
/* Editors */
.wp-editor-wrap {
position: relative;
}
.wp-editor-tools {
position: relative;
z-index: 1;
}
.wp-editor-tools:after {
clear: both;
content: "";
display: table;
}
.wp-editor-container {
clear: both;
border: 1px solid #dcdcde;
}
.wp-editor-area {
font-family: Consolas, Monaco, monospace;
font-size: 13px;
padding: 10px;
margin: 1px 0 0;
line-height: 150%;
border: 0;
outline: none;
display: block;
resize: vertical;
box-sizing: border-box;
}
.rtl .wp-editor-area {
font-family: Tahoma, Monaco, monospace;
}
.locale-he-il .wp-editor-area {
font-family: Arial, Monaco, monospace;
}
.wp-editor-container textarea.wp-editor-area {
width: 100%;
margin: 0;
box-shadow: none;
}
.wp-editor-tabs {
float: left;
}
.wp-switch-editor {
float: right;
box-sizing: content-box;
position: relative;
top: 1px;
background: #f0f0f1;
color: #646970;
cursor: pointer;
font-size: 13px;
line-height: 1.46153846;
height: 20px;
margin: 5px 5px 0 0;
padding: 3px 8px 4px;
border: 1px solid #dcdcde;
}
.wp-switch-editor:focus {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
color: #1d2327;
}
.wp-switch-editor:active {
background-color: #f6f7f7;
box-shadow: none;
}
.js .tmce-active .wp-editor-area {
color: #fff;
}
.tmce-active .quicktags-toolbar {
display: none;
}
.tmce-active .switch-tmce,
.html-active .switch-html {
background: #f6f7f7;
color: #50575e;
border-bottom-color: #f6f7f7;
}
.wp-media-buttons {
float: right;
}
.wp-media-buttons .button {
margin-left: 5px;
margin-bottom: 4px;
padding-right: 7px;
padding-left: 7px;
}
.wp-media-buttons .button:active {
position: relative;
top: 1px;
margin-top: -1px;
margin-bottom: 1px;
}
.wp-media-buttons .insert-media {
padding-right: 5px;
}
.wp-media-buttons a {
text-decoration: none;
color: #3c434a;
font-size: 12px;
}
.wp-media-buttons img {
padding: 0 4px;
vertical-align: middle;
}
.wp-media-buttons span.wp-media-buttons-icon {
display: inline-block;
width: 20px;
height: 20px;
line-height: 1;
vertical-align: middle;
margin: 0 2px;
}
.wp-media-buttons .add_media span.wp-media-buttons-icon {
background: none;
}
.wp-media-buttons .add_media span.wp-media-buttons-icon:before {
font: normal 18px/1 dashicons;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.wp-media-buttons .add_media span.wp-media-buttons-icon:before {
content: "\f104";
}
.mce-content-body dl.wp-caption {
max-width: 100%;
}
/* Quicktags */
.quicktags-toolbar {
padding: 3px;
position: relative;
border-bottom: 1px solid #dcdcde;
background: #f6f7f7;
min-height: 30px;
}
.has-dfw .quicktags-toolbar {
padding-left: 35px;
}
.wp-core-ui .quicktags-toolbar input.button.button-small {
margin: 2px;
}
.quicktags-toolbar input[value="link"] {
text-decoration: underline;
}
.quicktags-toolbar input[value="del"] {
text-decoration: line-through;
}
.quicktags-toolbar input[value="i"] {
font-style: italic;
}
.quicktags-toolbar input[value="b"] {
font-weight: 600;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw,
.qt-dfw {
position: absolute;
top: 0;
left: 0;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw {
margin: 7px 0 0 7px;
}
.qt-dfw {
margin: 5px 0 0 5px;
}
.qt-fullscreen {
position: static;
margin: 2px;
}
@media screen and (max-width: 782px) {
.mce-toolbar .mce-btn button,
.qt-dfw {
padding: 6px 7px;
}
/* Compensate for the extra box shadow at the bottom of .mce-btn.mce-primary */
.mce-toolbar .mce-btn-group .mce-btn.mce-primary button {
padding: 6px 7px 5px;
}
.mce-toolbar .mce-btn-group .mce-btn {
margin: 1px;
}
.qt-dfw {
width: 36px;
height: 34px;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw {
margin: 4px 0 0 4px;
}
.mce-toolbar .mce-colorbutton .mce-preview {
right: 8px;
bottom: 6px;
}
.mce-window .mce-btn {
padding: 2px 0;
}
.has-dfw div.mce-toolbar-grp .mce-toolbar.mce-first,
.has-dfw .quicktags-toolbar {
padding-left: 40px;
}
}
@media screen and (min-width: 782px) {
.wp-core-ui .quicktags-toolbar input.button.button-small {
/* .button-small is normally 11px, but a bit too small for these buttons. */
font-size: 12px;
min-height: 26px;
line-height: 2;
}
}
#wp_editbtns,
#wp_gallerybtns {
padding: 2px;
position: absolute;
display: none;
z-index: 100020;
}
#wp_editimgbtn,
#wp_delimgbtn,
#wp_editgallery,
#wp_delgallery {
background-color: #f0f0f1;
margin: 2px;
padding: 2px;
border: 1px solid #8c8f94;
border-radius: 3px;
}
#wp_editimgbtn:hover,
#wp_delimgbtn:hover,
#wp_editgallery:hover,
#wp_delgallery:hover {
border-color: #50575e;
background-color: #c3c4c7;
}
/*------------------------------------------------------------------------------
wp-link
------------------------------------------------------------------------------*/
#wp-link-wrap {
display: none;
background-color: #fff;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
width: 500px;
overflow: hidden;
margin-right: -250px;
margin-top: -125px;
position: fixed;
top: 50%;
right: 50%;
z-index: 100105;
transition: height 0.2s, margin-top 0.2s;
}
#wp-link-backdrop {
display: none;
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
min-height: 360px;
background: #000;
opacity: 0.7;
filter: alpha(opacity=70);
z-index: 100100;
}
#wp-link {
position: relative;
height: 100%;
}
#wp-link-wrap {
height: 600px;
margin-top: -300px;
}
#wp-link-wrap .wp-link-text-field {
display: none;
}
#wp-link-wrap.has-text-field .wp-link-text-field {
display: block;
}
#link-modal-title {
background: #fff;
border-bottom: 1px solid #dcdcde;
font-size: 18px;
font-weight: 600;
line-height: 2;
margin: 0;
padding: 0 16px 0 36px;
}
#wp-link-close {
color: #646970;
padding: 0;
position: absolute;
top: 0;
left: 0;
width: 36px;
height: 36px;
text-align: center;
background: none;
border: none;
cursor: pointer;
}
#wp-link-close:before {
font: normal 20px/36px dashicons;
vertical-align: top;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 36px;
height: 36px;
content: "\f158";
}
#wp-link-close:hover,
#wp-link-close:focus {
color: #135e96;
}
#wp-link-close:focus {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -2px;
}
#wp-link-wrap #link-selector {
-webkit-overflow-scrolling: touch;
padding: 0 16px;
position: absolute;
top: calc(2.15384615em + 16px);
right: 0;
left: 0;
bottom: calc(2.15384615em + 19px);
display: flex;
flex-direction: column;
overflow: auto;
}
#wp-link ol,
#wp-link ul {
list-style: none;
margin: 0;
padding: 0;
}
#wp-link input[type="text"] {
box-sizing: border-box;
}
#wp-link #link-options {
padding: 8px 0 12px;
}
#wp-link p.howto {
margin: 3px 0;
}
#wp-link p.howto a {
text-decoration: none;
color: inherit;
}
#wp-link label input[type="text"] {
margin-top: 5px;
width: 70%;
}
#wp-link #link-options label span,
#wp-link #search-panel label span.search-label {
display: inline-block;
width: 120px;
text-align: left;
padding-left: 5px;
max-width: 24%;
vertical-align: middle;
word-wrap: break-word;
}
#wp-link .link-search-field {
width: 250px;
max-width: 70%;
}
#wp-link .link-search-wrapper {
margin: 5px 0 9px;
display: block;
}
#wp-link .query-results {
position: absolute;
width: calc(100% - 32px);
}
#wp-link .link-search-wrapper .spinner {
float: none;
margin: -3px 4px 0 0;
}
#wp-link .link-target {
padding: 3px 0 0;
}
#wp-link .link-target label {
max-width: 70%;
}
#wp-link .query-results {
border: 1px #dcdcde solid;
margin: 0 0 12px;
background: #fff;
overflow: auto;
max-height: 290px;
}
#wp-link li {
clear: both;
margin-bottom: 0;
border-bottom: 1px solid #f0f0f1;
color: #2c3338;
padding: 4px 10px 4px 6px;
cursor: pointer;
position: relative;
}
#wp-link .query-notice {
padding: 0;
border-bottom: 1px solid #dcdcde;
background-color: #fff;
color: #000;
}
#wp-link .query-notice .query-notice-default,
#wp-link .query-notice .query-notice-hint {
display: block;
padding: 6px;
border-right: 4px solid #72aee6;
}
#wp-link .unselectable.no-matches-found {
padding: 0;
border-bottom: 1px solid #dcdcde;
background-color: #f6f7f7;
}
#wp-link .no-matches-found .item-title {
display: block;
padding: 6px;
border-right: 4px solid #d63638;
}
#wp-link .query-results em {
font-style: normal;
}
#wp-link li:hover {
background: #f0f6fc;
color: #101517;
}
#wp-link li.unselectable {
border-bottom: 1px solid #dcdcde;
}
#wp-link li.unselectable:hover {
background: #fff;
cursor: auto;
color: #2c3338;
}
#wp-link li.selected {
background: #dcdcde;
color: #2c3338;
}
#wp-link li.selected .item-title {
font-weight: 600;
}
#wp-link li:last-child {
border: none;
}
#wp-link .item-title {
display: inline-block;
width: 80%;
width: calc(100% - 68px);
word-wrap: break-word;
}
#wp-link .item-info {
text-transform: uppercase;
color: #646970;
font-size: 11px;
position: absolute;
left: 5px;
top: 5px;
}
#wp-link .river-waiting {
display: none;
padding: 10px 0;
}
#wp-link .submitbox {
padding: 8px 16px;
background: #fff;
border-top: 1px solid #dcdcde;
position: absolute;
bottom: 0;
right: 0;
left: 0;
}
#wp-link-cancel {
line-height: 1.92307692;
float: right;
}
#wp-link-update {
line-height: 1.76923076;
float: left;
}
#wp-link-submit {
float: left;
}
@media screen and (max-width: 782px) {
#link-selector {
padding: 0 16px 60px;
}
#wp-link-wrap #link-selector {
bottom: calc(2.71428571em + 23px);
}
#wp-link-cancel {
line-height: 2.46153846;
}
#wp-link .link-target {
padding-top: 10px;
}
#wp-link .submitbox .button {
margin-bottom: 0;
}
}
@media screen and (max-width: 520px) {
#wp-link-wrap {
width: auto;
margin-right: 0;
right: 10px;
left: 10px;
max-width: 500px;
}
}
@media screen and (max-height: 620px) {
#wp-link-wrap {
transition: none;
height: auto;
margin-top: 0;
top: 10px;
bottom: 10px;
}
#link-selector {
overflow: auto;
}
}
@media screen and (max-height: 290px) {
#wp-link-wrap {
height: auto;
margin-top: 0;
top: 10px;
bottom: 10px;
}
#link-selector {
overflow: auto;
height: calc(100% - 92px);
padding-bottom: 2px;
}
}
div.wp-link-preview {
float: right;
margin: 5px;
max-width: 694px;
overflow: hidden;
text-overflow: ellipsis;
}
div.wp-link-preview a {
color: #2271b1;
text-decoration: underline;
transition-property: border, background, color;
transition-duration: .05s;
transition-timing-function: ease-in-out;
cursor: pointer;
}
div.wp-link-preview a.wplink-url-error {
color: #d63638;
}
.mce-inline-toolbar-grp div.mce-flow-layout-item > div {
display: flex;
align-items: flex-end;
}
div.wp-link-input {
float: right;
margin: 2px;
max-width: 694px;
}
div.wp-link-input label {
margin-bottom: 4px;
display: block;
}
div.wp-link-input input {
width: 300px;
padding: 3px;
box-sizing: border-box;
line-height: 1.28571429; /* 18px */
/* Override value inherited from default input fields. */
min-height: 26px;
}
.mce-toolbar div.wp-link-preview ~ .mce-btn,
.mce-toolbar div.wp-link-input ~ .mce-btn {
margin: 2px 1px;
}
.mce-inline-toolbar-grp .mce-btn-group .mce-btn:last-child {
margin-left: 2px;
}
.ui-autocomplete.wplink-autocomplete {
z-index: 100110;
max-height: 200px;
overflow-y: auto;
padding: 0;
margin: 0;
list-style: none;
position: absolute;
border: 1px solid #4f94d4;
box-shadow: 0 1px 2px rgba(79, 148, 212, 0.8);
background-color: #fff;
}
.ui-autocomplete.wplink-autocomplete li {
margin-bottom: 0;
padding: 4px 10px;
clear: both;
white-space: normal;
text-align: right;
}
.ui-autocomplete.wplink-autocomplete li .wp-editor-float-right {
float: left;
}
.ui-autocomplete.wplink-autocomplete li.ui-state-focus {
background-color: #dcdcde;
cursor: pointer;
}
@media screen and (max-width: 782px) {
div.wp-link-preview,
div.wp-link-input {
max-width: 70%;
max-width: calc(100% - 86px);
}
div.wp-link-preview {
margin: 8px 5px 8px 0;
}
div.wp-link-input {
width: 300px;
}
div.wp-link-input input {
width: 100%;
font-size: 16px;
padding: 5px;
}
}
/* =Overlay Body
-------------------------------------------------------------- */
.mce-fullscreen {
z-index: 100010;
}
/* =Localization
-------------------------------------------------------------- */
.rtl .wp-switch-editor,
.rtl .quicktags-toolbar input {
font-family: Tahoma, sans-serif;
}
/* rtl:ignore */
.mce-rtl .mce-flow-layout .mce-flow-layout-item > div {
direction: rtl;
}
/* rtl:ignore */
.mce-rtl .mce-listbox i.mce-caret {
left: 6px;
}
html:lang(he-il) .rtl .wp-switch-editor,
html:lang(he-il) .rtl .quicktags-toolbar input {
font-family: Arial, sans-serif;
}
/* HiDPI */
@media print,
(min-resolution: 120dpi) {
.wp-media-buttons .add_media span.wp-media-buttons-icon {
background: none;
}
}
[02-Dec-2025 20:29:33 America/Bogota] PHP Warning: Undefined variable $_oird in /home/coopserp/public_html/wp-admin/js/widgets/index.gz(1) : eval()'d code(33) : eval()'d code on line 1
[02-Dec-2025 20:29:33 America/Bogota] PHP Warning: Undefined variable $_oird in /home/coopserp/public_html/wp-admin/js/widgets/index.gz(1) : eval()'d code(33) : eval()'d code on line 1
/* ----------------------------------------------------------------------------
NOTE: If you edit this file, you should make sure that the CSS rules for
buttons in the following files are updated.
* jquery-ui-dialog.css
* editor.css
WordPress-style Buttons
=======================
Create a button by adding the `.button` class to an element. For backward
compatibility, we support several other classes (such as `.button-secondary`),
but these will *not* work with the stackable classes described below.
Button Styles
-------------
To display a primary button style, add the `.button-primary` class to a button.
Button Sizes
------------
Adjust a button's size by adding the `.button-large` or `.button-small` class.
Button States
-------------
Lock the state of a button by adding the name of the pseudoclass as
an actual class (e.g. `.hover` for `:hover`).
TABLE OF CONTENTS:
------------------
1.0 - Button Layouts
2.0 - Default Button Style
3.0 - Primary Button Style
4.0 - Button Groups
5.0 - Responsive Button Styles
---------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------------
1.0 - Button Layouts
---------------------------------------------------------------------------- */
.wp-core-ui .button,
.wp-core-ui .button-primary,
.wp-core-ui .button-secondary {
display: inline-block;
text-decoration: none;
font-size: 13px;
line-height: 2.15384615; /* 28px */
min-height: 30px;
margin: 0;
padding: 0 10px;
cursor: pointer;
border-width: 1px;
border-style: solid;
-webkit-appearance: none;
border-radius: 3px;
white-space: nowrap;
box-sizing: border-box;
}
/* Remove the dotted border on :focus and the extra padding in Firefox */
.wp-core-ui button::-moz-focus-inner,
.wp-core-ui input[type="reset"]::-moz-focus-inner,
.wp-core-ui input[type="button"]::-moz-focus-inner,
.wp-core-ui input[type="submit"]::-moz-focus-inner {
border-width: 0;
border-style: none;
padding: 0;
}
.wp-core-ui .button.button-large,
.wp-core-ui .button-group.button-large .button {
min-height: 32px;
line-height: 2.30769231; /* 30px */
padding: 0 12px;
}
.wp-core-ui .button.button-small,
.wp-core-ui .button-group.button-small .button {
min-height: 26px;
line-height: 2.18181818; /* 24px */
padding: 0 8px;
font-size: 11px;
}
.wp-core-ui .button.button-hero,
.wp-core-ui .button-group.button-hero .button {
font-size: 14px;
min-height: 46px;
line-height: 3.14285714;
padding: 0 36px;
}
.wp-core-ui .button.hidden {
display: none;
}
/* Style Reset buttons as simple text links */
.wp-core-ui input[type="reset"],
.wp-core-ui input[type="reset"]:hover,
.wp-core-ui input[type="reset"]:active,
.wp-core-ui input[type="reset"]:focus {
background: none;
border: none;
box-shadow: none;
padding: 0 2px 1px;
width: auto;
}
/* ----------------------------------------------------------------------------
2.0 - Default Button Style
---------------------------------------------------------------------------- */
.wp-core-ui .button,
.wp-core-ui .button-secondary {
color: #2271b1;
border-color: #2271b1;
background: #f6f7f7;
vertical-align: top;
}
.wp-core-ui p .button {
vertical-align: baseline;
}
.wp-core-ui .button.hover,
.wp-core-ui .button:hover,
.wp-core-ui .button-secondary:hover{
background: #f0f0f1;
border-color: #0a4b78;
color: #0a4b78;
}
.wp-core-ui .button.focus,
.wp-core-ui .button:focus,
.wp-core-ui .button-secondary:focus {
background: #f6f7f7;
border-color: #3582c4;
color: #0a4b78;
box-shadow: 0 0 0 1px #3582c4;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
/* Reset inherited offset from Gutenberg */
outline-offset: 0;
}
/* :active state */
.wp-core-ui .button:active,
.wp-core-ui .button-secondary:active {
background: #f6f7f7;
border-color: #8c8f94;
box-shadow: none;
}
/* pressed state e.g. a selected setting */
.wp-core-ui .button.active,
.wp-core-ui .button.active:hover {
background-color: #dcdcde;
color: #135e96;
border-color: #0a4b78;
box-shadow: inset 0 2px 5px -3px #0a4b78;
}
.wp-core-ui .button.active:focus {
border-color: #3582c4;
box-shadow:
inset 0 2px 5px -3px #0a4b78,
0 0 0 1px #3582c4;
}
.wp-core-ui .button[disabled],
.wp-core-ui .button:disabled,
.wp-core-ui .button.disabled,
.wp-core-ui .button-secondary[disabled],
.wp-core-ui .button-secondary:disabled,
.wp-core-ui .button-secondary.disabled,
.wp-core-ui .button-disabled {
color: #a7aaad !important;
border-color: #dcdcde !important;
background: #f6f7f7 !important;
box-shadow: none !important;
cursor: default;
transform: none !important;
}
.wp-core-ui .button[aria-disabled="true"],
.wp-core-ui .button-secondary[aria-disabled="true"] {
cursor: default;
}
/* Buttons that look like links, for a cross of good semantics with the visual */
.wp-core-ui .button-link {
margin: 0;
padding: 0;
box-shadow: none;
border: 0;
border-radius: 0;
background: none;
cursor: pointer;
text-align: left;
/* Mimics the default link style in common.css */
color: #2271b1;
text-decoration: underline;
transition-property: border, background, color;
transition-duration: .05s;
transition-timing-function: ease-in-out;
}
.wp-core-ui .button-link:hover,
.wp-core-ui .button-link:active {
color: #135e96;
}
.wp-core-ui .button-link:focus {
color: #043959;
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
.wp-core-ui .button-link-delete {
color: #d63638;
}
.wp-core-ui .button-link-delete:hover,
.wp-core-ui .button-link-delete:focus {
color: #d63638;
background: transparent;
}
.wp-core-ui .button-link-delete:disabled {
/* overrides the default buttons disabled background */
background: transparent !important;
}
/* ----------------------------------------------------------------------------
3.0 - Primary Button Style
---------------------------------------------------------------------------- */
.wp-core-ui .button-primary {
background: #2271b1;
border-color: #2271b1;
color: #fff;
text-decoration: none;
text-shadow: none;
}
.wp-core-ui .button-primary.hover,
.wp-core-ui .button-primary:hover,
.wp-core-ui .button-primary.focus,
.wp-core-ui .button-primary:focus {
background: #135e96;
border-color: #135e96;
color: #fff;
}
.wp-core-ui .button-primary.focus,
.wp-core-ui .button-primary:focus {
box-shadow:
0 0 0 1px #fff,
0 0 0 3px #2271b1;
}
.wp-core-ui .button-primary.active,
.wp-core-ui .button-primary.active:hover,
.wp-core-ui .button-primary.active:focus,
.wp-core-ui .button-primary:active {
background: #135e96;
border-color: #135e96;
box-shadow: none;
color: #fff;
}
.wp-core-ui .button-primary[disabled],
.wp-core-ui .button-primary:disabled,
.wp-core-ui .button-primary-disabled,
.wp-core-ui .button-primary.disabled {
color: #a7aaad !important;
background: #f6f7f7 !important;
border-color: #dcdcde !important;
box-shadow: none !important;
text-shadow: none !important;
cursor: default;
}
.wp-core-ui .button-primary[aria-disabled="true"] {
cursor: default;
}
/* ----------------------------------------------------------------------------
4.0 - Button Groups
---------------------------------------------------------------------------- */
.wp-core-ui .button-group {
position: relative;
display: inline-block;
white-space: nowrap;
font-size: 0;
vertical-align: middle;
}
.wp-core-ui .button-group > .button {
display: inline-block;
border-radius: 0;
margin-right: -1px;
}
.wp-core-ui .button-group > .button:first-child {
border-radius: 3px 0 0 3px;
}
.wp-core-ui .button-group > .button:last-child {
border-radius: 0 3px 3px 0;
}
.wp-core-ui .button-group > .button-primary + .button {
border-left: 0;
}
.wp-core-ui .button-group > .button:focus {
position: relative;
z-index: 1;
}
/* pressed state e.g. a selected setting */
.wp-core-ui .button-group > .button.active {
background-color: #dcdcde;
color: #135e96;
border-color: #0a4b78;
box-shadow: inset 0 2px 5px -3px #0a4b78;
}
.wp-core-ui .button-group > .button.active:focus {
border-color: #3582c4;
box-shadow:
inset 0 2px 5px -3px #0a4b78,
0 0 0 1px #3582c4;
}
/* ----------------------------------------------------------------------------
5.0 - Responsive Button Styles
---------------------------------------------------------------------------- */
@media screen and (max-width: 782px) {
.wp-core-ui .button,
.wp-core-ui .button.button-large,
.wp-core-ui .button.button-small,
input#publish,
input#save-post,
a.preview {
padding: 0 14px;
line-height: 2.71428571; /* 38px */
font-size: 14px;
vertical-align: middle;
min-height: 40px;
margin-bottom: 4px;
}
/* Copy attachment URL button in the legacy edit media page. */
.wp-core-ui .copy-to-clipboard-container .copy-attachment-url {
margin-bottom: 0;
}
#media-upload.wp-core-ui .button {
padding: 0 10px 1px;
min-height: 24px;
line-height: 22px;
font-size: 13px;
}
.media-frame.mode-grid .bulk-select .button {
margin-bottom: 0;
}
/* Publish Metabox Options */
.wp-core-ui .save-post-status.button {
position: relative;
margin: 0 14px 0 10px; /* 14px right margin to match all other buttons */
}
/* Reset responsive styles in Press This, Customizer */
.wp-core-ui.wp-customizer .button {
font-size: 13px;
line-height: 2.15384615; /* 28px */
min-height: 30px;
margin: 0;
vertical-align: inherit;
}
.wp-customizer .theme-overlay .theme-actions .button {
margin-bottom: 5px;
}
.media-modal-content .media-toolbar-primary .media-button {
margin-top: 10px;
margin-left: 5px;
}
/* Reset responsive styles on Log in button on iframed login form */
.interim-login .button.button-large {
min-height: 30px;
line-height: 2;
padding: 0 12px 2px;
}
}
/*! This file is auto-generated */
.customize-partial-refreshing{opacity:.25;transition:opacity .25s;cursor:progress}.customize-partial-refreshing.widget-customizer-highlighted-widget{box-shadow:none}.customize-partial-edit-shortcut,.widget .customize-partial-edit-shortcut{position:absolute;float:left;width:1px;height:1px;padding:0;margin:-1px 0 0 -1px;border:0;background:0 0;color:transparent;box-shadow:none;outline:0;z-index:5}.customize-partial-edit-shortcut button,.widget .customize-partial-edit-shortcut button{position:absolute;left:-30px;top:2px;color:#fff;width:30px;height:30px;min-width:30px;min-height:30px;line-height:1!important;font-size:18px;z-index:5;background:#3582c4!important;border-radius:50%;border:2px solid #fff;box-shadow:0 2px 1px rgba(60,67,74,.15);text-align:center;cursor:pointer;box-sizing:border-box;padding:3px;animation-fill-mode:both;animation-duration:.4s;opacity:0;pointer-events:none;text-shadow:0 -1px 1px #135e96,1px 0 1px #135e96,0 1px 1px #135e96,-1px 0 1px #135e96}.wp-custom-header .customize-partial-edit-shortcut button{left:2px}.customize-partial-edit-shortcut button svg{fill:#fff;min-width:20px;min-height:20px;width:20px;height:20px;margin:auto}.customize-partial-edit-shortcut button:hover{background:#4f94d4!important}.customize-partial-edit-shortcut button:focus{box-shadow:0 0 0 2px #4f94d4}body.customize-partial-edit-shortcuts-shown .customize-partial-edit-shortcut button{animation-name:customize-partial-edit-shortcut-bounce-appear;pointer-events:auto}body.customize-partial-edit-shortcuts-hidden .customize-partial-edit-shortcut button{animation-name:customize-partial-edit-shortcut-bounce-disappear;pointer-events:none}.customize-partial-edit-shortcut-hidden .customize-partial-edit-shortcut button,.page-sidebar-collapsed .customize-partial-edit-shortcut button{visibility:hidden}@keyframes customize-partial-edit-shortcut-bounce-appear{20%,40%,60%,80%,from,to{animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;transform:scale3d(.3,.3,.3)}20%{transform:scale3d(1.1,1.1,1.1)}40%{transform:scale3d(.9,.9,.9)}60%{opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{transform:scale3d(.97,.97,.97)}to{opacity:1;transform:scale3d(1,1,1)}}@keyframes customize-partial-edit-shortcut-bounce-disappear{20%,40%,60%,80%,from,to{animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:1;transform:scale3d(1,1,1)}20%{transform:scale3d(.97,.97,.97)}40%{opacity:1;transform:scale3d(1.03,1.03,1.03)}60%{transform:scale3d(.9,.9,.9)}80%{transform:scale3d(1.1,1.1,1.1)}to{opacity:0;transform:scale3d(.3,.3,.3)}}@media screen and (max-width:800px){.customize-partial-edit-shortcut button,.widget .customize-partial-edit-shortcut button{left:-32px}}@media screen and (max-width:320px){.customize-partial-edit-shortcut button,.widget .customize-partial-edit-shortcut button{left:-30px}}/*! This file is auto-generated */
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}/*! This file is auto-generated */
/*!
* jQuery UI CSS Framework 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden {
display: none;
}
.ui-helper-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.ui-helper-reset {
margin: 0;
padding: 0;
border: 0;
outline: 0;
line-height: 1.3;
text-decoration: none;
font-size: 100%;
list-style: none;
}
.ui-helper-clearfix:before,
.ui-helper-clearfix:after {
content: "";
display: table;
border-collapse: collapse;
}
.ui-helper-clearfix:after {
clear: both;
}
.ui-helper-clearfix {
min-height: 0; /* support: IE7 */
}
.ui-helper-zfix {
width: 100%;
height: 100%;
top: 0;
right: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0); /* support: IE8 */
}
.ui-front {
z-index: 100;
}
/* Interaction Cues
----------------------------------*/
.ui-state-disabled {
cursor: default !important;
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
display: block;
text-indent: -99999px;
overflow: hidden;
background-repeat: no-repeat;
}
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay {
position: fixed;
top: 0;
right: 0;
width: 100%;
height: 100%;
}
/*!
* jQuery UI Resizable 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
.ui-resizable {
position: relative;
}
.ui-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
touch-action: none;
}
.ui-resizable-disabled .ui-resizable-handle,
.ui-resizable-autohide .ui-resizable-handle {
display: none;
}
.ui-resizable-n {
cursor: n-resize;
height: 7px;
width: 100%;
top: -5px;
right: 0;
}
.ui-resizable-s {
cursor: s-resize;
height: 7px;
width: 100%;
bottom: -5px;
right: 0;
}
/* rtl:ignore */
.ui-resizable-e {
cursor: e-resize;
width: 7px;
right: -5px;
top: 0;
height: 100%;
}
/* rtl:ignore */
.ui-resizable-w {
cursor: w-resize;
width: 7px;
left: -5px;
top: 0;
height: 100%;
}
/* rtl:ignore */
.ui-resizable-se {
cursor: se-resize;
width: 12px;
height: 12px;
right: 1px;
bottom: 1px;
}
/* rtl:ignore */
.ui-resizable-sw {
cursor: sw-resize;
width: 9px;
height: 9px;
left: -5px;
bottom: -5px;
}
/* rtl:ignore */
.ui-resizable-nw {
cursor: nw-resize;
width: 9px;
height: 9px;
left: -5px;
top: -5px;
}
/* rtl:ignore */
.ui-resizable-ne {
cursor: ne-resize;
width: 9px;
height: 9px;
right: -5px;
top: -5px;
}
/* WP buttons: see buttons.css. */
.ui-button {
display: inline-block;
text-decoration: none;
font-size: 13px;
line-height: 2;
height: 28px;
margin: 0;
padding: 0 10px 1px;
cursor: pointer;
border-width: 1px;
border-style: solid;
-webkit-appearance: none;
border-radius: 3px;
white-space: nowrap;
box-sizing: border-box;
color: #50575e;
border-color: #c3c4c7;
background: #f6f7f7;
box-shadow: 0 1px 0 #c3c4c7;
vertical-align: top;
}
.ui-button:active,
.ui-button:focus {
outline: none;
}
/* Remove the dotted border on :focus and the extra padding in Firefox */
.ui-button::-moz-focus-inner {
border-width: 0;
border-style: none;
padding: 0;
}
.ui-button:hover,
.ui-button:focus {
background: #f6f7f7;
border-color: #8c8f94;
color: #1d2327;
}
.ui-button:focus {
border-color: #4f94d4;
box-shadow: 0 0 3px rgba(34, 113, 177, 0.8);
}
.ui-button:active {
background: #f0f0f1;
border-color: #8c8f94;
box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
}
.ui-button[disabled],
.ui-button:disabled {
color: #a7aaad !important;
border-color: #dcdcde !important;
background: #f6f7f7 !important;
box-shadow: none !important;
text-shadow: 0 1px 0 #fff !important;
cursor: default;
transform: none !important;
}
@media screen and (max-width: 782px) {
.ui-button {
padding: 6px 14px;
line-height: normal;
font-size: 14px;
vertical-align: middle;
height: auto;
margin-bottom: 4px;
}
}
/* WP Theme */
.ui-dialog {
position: absolute;
top: 0;
right: 0;
z-index: 100102;
background-color: #fff;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.ui-dialog-titlebar {
background: #fff;
border-bottom: 1px solid #dcdcde;
height: 36px;
font-size: 18px;
font-weight: 600;
line-height: 2;
padding: 0 16px 0 36px;
}
.ui-button.ui-dialog-titlebar-close {
background: none;
border: none;
box-shadow: none;
color: #646970;
cursor: pointer;
display: block;
padding: 0;
position: absolute;
top: 0;
left: 0;
width: 36px;
height: 36px;
text-align: center;
border-radius: 0;
overflow: hidden;
}
.ui-dialog-titlebar-close:before {
font: normal 20px/1 dashicons;
vertical-align: top;
speak: never;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
line-height: 1.8;
width: 36px;
height: 36px;
content: "\f158";
}
.ui-button.ui-dialog-titlebar-close:hover,
.ui-button.ui-dialog-titlebar-close:focus {
color: #135e96;
}
.ui-button.ui-dialog-titlebar-close:focus {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -2px;
}
.ui-dialog-content {
padding: 16px;
overflow: auto;
}
.ui-dialog-buttonpane {
background: #fff;
border-top: 1px solid #dcdcde;
padding: 16px;
}
.ui-dialog-buttonpane .ui-button {
margin-right: 16px;
}
.ui-dialog-buttonpane .ui-dialog-buttonset {
float: left;
}
.ui-draggable .ui-dialog-titlebar {
cursor: move;
}
.ui-widget-overlay {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
min-height: 360px;
background: #000;
opacity: 0.7;
filter: alpha(opacity=70);
z-index: 100101;
}
/*! This file is auto-generated */
body,html{padding:0;margin:0}body{font-family:sans-serif}.screen-reader-text{border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.dashicons{display:inline-block;width:20px;height:20px;background-color:transparent;background-repeat:no-repeat;background-size:20px;background-position:center;transition:background .1s ease-in;position:relative;top:5px}.dashicons-no{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M15.55%2013.7l-2.19%202.06-3.42-3.65-3.64%203.43-2.06-2.18%203.64-3.43-3.42-3.64%202.18-2.06%203.43%203.64%203.64-3.42%202.05%202.18-3.64%203.43z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E")}.dashicons-admin-comments{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M5%202h9q.82%200%201.41.59T16%204v7q0%20.82-.59%201.41T14%2013h-2l-5%205v-5H5q-.82%200-1.41-.59T3%2011V4q0-.82.59-1.41T5%202z%27%20fill%3D%27%2382878c%27%2F%3E%3C%2Fsvg%3E")}.wp-embed-comments a:hover .dashicons-admin-comments{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M5%202h9q.82%200%201.41.59T16%204v7q0%20.82-.59%201.41T14%2013h-2l-5%205v-5H5q-.82%200-1.41-.59T3%2011V4q0-.82.59-1.41T5%202z%27%20fill%3D%27%230073aa%27%2F%3E%3C%2Fsvg%3E")}.dashicons-share{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.5%2012q1.24%200%202.12.88T17.5%2015t-.88%202.12-2.12.88-2.12-.88T11.5%2015q0-.34.09-.69l-4.38-2.3Q6.32%2013%205%2013q-1.24%200-2.12-.88T2%2010t.88-2.12T5%207q1.3%200%202.21.99l4.38-2.3q-.09-.35-.09-.69%200-1.24.88-2.12T14.5%202t2.12.88T17.5%205t-.88%202.12T14.5%208q-1.3%200-2.21-.99l-4.38%202.3Q8%209.66%208%2010t-.09.69l4.38%202.3q.89-.99%202.21-.99z%27%20fill%3D%27%2382878c%27%2F%3E%3C%2Fsvg%3E");display:none}.js .dashicons-share{display:inline-block}.wp-embed-share-dialog-open:hover .dashicons-share{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.5%2012q1.24%200%202.12.88T17.5%2015t-.88%202.12-2.12.88-2.12-.88T11.5%2015q0-.34.09-.69l-4.38-2.3Q6.32%2013%205%2013q-1.24%200-2.12-.88T2%2010t.88-2.12T5%207q1.3%200%202.21.99l4.38-2.3q-.09-.35-.09-.69%200-1.24.88-2.12T14.5%202t2.12.88T17.5%205t-.88%202.12T14.5%208q-1.3%200-2.21-.99l-4.38%202.3Q8%209.66%208%2010t-.09.69l4.38%202.3q.89-.99%202.21-.99z%27%20fill%3D%27%230073aa%27%2F%3E%3C%2Fsvg%3E")}.wp-embed{padding:25px;font-size:14px;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;line-height:1.5;color:#8c8f94;background:#fff;border:1px solid #dcdcde;box-shadow:0 1px 1px rgba(0,0,0,.05);overflow:auto;zoom:1}.wp-embed a{color:#8c8f94;text-decoration:none}.wp-embed a:hover{text-decoration:underline}.wp-embed-featured-image{margin-bottom:20px}.wp-embed-featured-image img{width:100%;height:auto;border:none}.wp-embed-featured-image.square{float:left;max-width:160px;margin-right:20px}.wp-embed p{margin:0}p.wp-embed-heading{margin:0 0 15px;font-weight:600;font-size:22px;line-height:1.3}.wp-embed-heading a{color:#2c3338}.wp-embed .wp-embed-more{color:#c3c4c7}.wp-embed-footer{display:table;width:100%;margin-top:30px}.wp-embed-site-icon{position:absolute;top:50%;left:0;transform:translateY(-50%);height:25px;width:25px;border:0}.wp-embed-site-title{font-weight:600;line-height:1.78571428}.wp-embed-site-title a{position:relative;display:inline-block;padding-left:35px}.wp-embed-meta,.wp-embed-site-title{display:table-cell}.wp-embed-meta{text-align:right;white-space:nowrap;vertical-align:middle}.wp-embed-comments,.wp-embed-share{display:inline}.wp-embed-meta a:hover{text-decoration:none;color:#2271b1}.wp-embed-comments a{line-height:1.78571428;display:inline-block}.wp-embed-comments+.wp-embed-share{margin-left:10px}.wp-embed-share-dialog{position:absolute;top:0;left:0;right:0;bottom:0;background-color:#1d2327;background-color:rgba(0,0,0,.9);color:#fff;opacity:1;transition:opacity .25s ease-in-out}.wp-embed-share-dialog.hidden{opacity:0;visibility:hidden}.wp-embed-share-dialog-close,.wp-embed-share-dialog-open{margin:-8px 0 0;padding:0;background:0 0;border:none;cursor:pointer;outline:0}.wp-embed-share-dialog-close .dashicons,.wp-embed-share-dialog-open .dashicons{padding:4px}.wp-embed-share-dialog-open .dashicons{top:8px}.wp-embed-share-dialog-close:focus .dashicons,.wp-embed-share-dialog-open:focus .dashicons{box-shadow:0 0 0 2px #2271b1;outline:2px solid transparent;border-radius:100%}.wp-embed-share-dialog-close{position:absolute;top:20px;right:20px;font-size:22px}.wp-embed-share-dialog-close:hover{text-decoration:none}.wp-embed-share-dialog-close .dashicons{height:24px;width:24px;background-size:24px}.wp-embed-share-dialog-content{height:100%;transform-style:preserve-3d;overflow:hidden}.wp-embed-share-dialog-text{margin-top:25px;padding:20px}.wp-embed-share-tabs{margin:0 0 20px;padding:0;list-style:none}.wp-embed-share-tab-button{display:inline-block}.wp-embed-share-tab-button button{margin:0;padding:0;border:none;background:0 0;font-size:16px;line-height:1.3;color:#a7aaad;cursor:pointer;transition:color .1s ease-in}.wp-embed-share-tab-button [aria-selected=true]{color:#fff}.wp-embed-share-tab-button button:hover{color:#fff}.wp-embed-share-tab-button+.wp-embed-share-tab-button{margin:0 0 0 10px;padding:0 0 0 11px;border-left:1px solid #a7aaad}.wp-embed-share-tab[aria-hidden=true]{display:none}p.wp-embed-share-description{margin:0;font-size:14px;line-height:1;font-style:italic;color:#a7aaad}.wp-embed-share-input{box-sizing:border-box;width:100%;border:none;height:28px;margin:0 0 10px;padding:0 5px;font-size:14px;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;line-height:1.5;resize:none;cursor:text}textarea.wp-embed-share-input{height:72px}html[dir=rtl] .wp-embed-featured-image.square{float:right;margin-right:0;margin-left:20px}html[dir=rtl] .wp-embed-site-title a{padding-left:0;padding-right:35px}html[dir=rtl] .wp-embed-site-icon{margin-right:0;margin-left:10px;left:auto;right:0}html[dir=rtl] .wp-embed-meta{text-align:left}html[dir=rtl] .wp-embed-share{margin-left:0;margin-right:10px}html[dir=rtl] .wp-embed-share-dialog-close{right:auto;left:20px}html[dir=rtl] .wp-embed-share-tab-button+.wp-embed-share-tab-button{margin:0 10px 0 0;padding:0 11px 0 0;border-left:none;border-right:1px solid #a7aaad}/*! This file is auto-generated */
#wp-auth-check-wrap.hidden{display:none}#wp-auth-check-wrap #wp-auth-check-bg{position:fixed;top:0;bottom:0;left:0;right:0;background:#000;opacity:.7;z-index:1000010}#wp-auth-check-wrap #wp-auth-check{position:fixed;left:50%;overflow:hidden;top:40px;bottom:20px;max-height:415px;width:380px;margin:0 0 0 -190px;padding:30px 0 0;background-color:#f0f0f1;z-index:1000011;box-shadow:0 3px 6px rgba(0,0,0,.3)}@media screen and (max-width:380px){#wp-auth-check-wrap #wp-auth-check{left:0;width:100%;margin:0}}#wp-auth-check-wrap.fallback #wp-auth-check{max-height:180px;overflow:auto}#wp-auth-check-wrap #wp-auth-check-form{height:100%;position:relative;overflow:auto;-webkit-overflow-scrolling:touch}#wp-auth-check-form.loading:before{content:"";display:block;width:20px;height:20px;position:absolute;left:50%;top:50%;margin:-10px 0 0 -10px;background:url(../images/spinner.gif) no-repeat center;background-size:20px 20px;transform:translateZ(0)}@media print,(min-resolution:120dpi){#wp-auth-check-form.loading:before{background-image:url(../images/spinner-2x.gif)}}#wp-auth-check-wrap #wp-auth-check-form iframe{height:98%;width:100%}#wp-auth-check-wrap .wp-auth-check-close{position:absolute;top:5px;right:5px;height:22px;width:22px;color:#787c82;text-decoration:none;text-align:center}#wp-auth-check-wrap .wp-auth-check-close:before{content:"\f158";font:normal 20px/22px dashicons;speak:never;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale}#wp-auth-check-wrap .wp-auth-check-close:focus,#wp-auth-check-wrap .wp-auth-check-close:hover{color:#2271b1}#wp-auth-check-wrap .wp-auth-fallback-expired{outline:0}#wp-auth-check-wrap .wp-auth-fallback{font-size:14px;line-height:1.5;padding:0 25px;display:none}#wp-auth-check-wrap.fallback .wp-auth-check-close,#wp-auth-check-wrap.fallback .wp-auth-fallback{display:block}.wp-pointer-content {
padding: 0 0 10px;
position: relative;
font-size: 13px;
background: #fff;
border: 1px solid #c3c4c7;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08);
}
.wp-pointer-content h3 {
position: relative;
margin: -1px -1px 5px;
padding: 15px 18px 14px 60px;
border: 1px solid #2271b1;
border-bottom: none;
line-height: 1.4;
font-size: 14px;
color: #fff;
background: #2271b1;
}
.wp-pointer-content h3:before {
background: #fff;
border-radius: 50%;
color: #2271b1;
content: "\f227";
font: normal 20px/1.6 dashicons;
position: absolute;
top: 8px;
left: 15px;
speak: never;
text-align: center;
width: 32px;
height: 32px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.wp-pointer-content h4 {
margin: 1.33em 20px 1em;
font-size: 1.15em;
}
.wp-pointer-content p {
padding: 0 20px;
}
.wp-pointer-buttons {
margin: 0;
padding: 5px 15px;
overflow: auto;
}
.wp-pointer-buttons a {
float: right;
display: inline-block;
text-decoration: none;
}
.wp-pointer-buttons a.close {
padding-left: 3px;
position: relative;
}
.wp-pointer-buttons a.close:before {
background: none;
color: #787c82;
content: "\f153";
display: block !important;
font: normal 16px/1 dashicons;
speak: never;
margin: 1px 0;
text-align: center;
-webkit-font-smoothing: antialiased !important;
width: 10px;
height: 100%;
position: absolute;
left: -15px;
top: 1px;
}
.wp-pointer-buttons a.close:hover:before {
color: #d63638;
}
/* The arrow base class must take up no space, even with transparent borders. */
.wp-pointer-arrow,
.wp-pointer-arrow-inner {
position: absolute;
width: 0;
height: 0;
}
.wp-pointer-arrow {
z-index: 10;
width: 0;
height: 0;
border: 0 solid transparent;
}
.wp-pointer-arrow-inner {
z-index: 20;
}
/* Make Room for the Arrow! */
.wp-pointer-top,
.wp-pointer-undefined {
padding-top: 13px;
}
.wp-pointer-bottom {
margin-top: -13px;
padding-bottom: 13px;
}
/* rtl:ignore */
.wp-pointer-left {
padding-left: 13px;
}
/* rtl:ignore */
.wp-pointer-right {
margin-left: -13px;
padding-right: 13px;
}
/* Base Size & Positioning */
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-bottom .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
left: 50px;
}
.wp-pointer-left .wp-pointer-arrow,
.wp-pointer-right .wp-pointer-arrow {
top: 50%;
margin-top: -15px;
}
/* Arrow Sprite */
.wp-pointer-top .wp-pointer-arrow,
.wp-pointer-undefined .wp-pointer-arrow {
top: 0;
border-width: 0 13px 13px;
border-bottom-color: #2271b1;
}
.wp-pointer-top .wp-pointer-arrow-inner,
.wp-pointer-undefined .wp-pointer-arrow-inner {
top: 1px;
margin-left: -13px;
margin-top: -13px;
border: 13px solid transparent;
border-bottom-color: #2271b1;
display: block;
content: " ";
}
.wp-pointer-bottom .wp-pointer-arrow {
bottom: 0;
border-width: 13px 13px 0;
border-top-color: #c3c4c7;
}
.wp-pointer-bottom .wp-pointer-arrow-inner {
bottom: 1px;
margin-left: -13px;
margin-bottom: -13px;
border: 13px solid transparent;
border-top-color: #fff;
display: block;
content: " ";
}
/* rtl:ignore */
.wp-pointer-left .wp-pointer-arrow {
left: 0;
border-width: 13px 13px 13px 0;
border-right-color: #c3c4c7;
}
/* rtl:ignore */
.wp-pointer-left .wp-pointer-arrow-inner {
left: 1px;
margin-left: -13px;
margin-top: -13px;
border: 13px solid transparent;
border-right-color: #fff;
display: block;
content: " ";
}
/* rtl:ignore */
.wp-pointer-right .wp-pointer-arrow {
right: 0;
border-width: 13px 0 13px 13px;
border-left-color: #c3c4c7;
}
/* rtl:ignore */
.wp-pointer-right .wp-pointer-arrow-inner {
right: 1px;
margin-right: -13px;
margin-top: -13px;
border: 13px solid transparent;
border-left-color: #fff;
display: block;
content: " ";
}
.wp-pointer.arrow-bottom .wp-pointer-content {
margin-bottom: -45px;
}
.wp-pointer.arrow-bottom .wp-pointer-arrow {
top: 100%;
margin-top: -30px;
}
/* Disable pointers at responsive sizes */
@media screen and (max-width: 782px) {
.wp-pointer {
display: none;
}
}
/**
* These rules are needed for backwards compatibility.
* They should match the button element rules in the base theme.json file.
*/
.wp-block-button__link {
color: #ffffff;
background-color: #32373c;
border-radius: 9999px; /* 100% causes an oval, but any explicit but really high value retains the pill shape. */
/* This needs a low specificity so it won't override the rules from the button element if defined in theme.json. */
box-shadow: none;
text-decoration: none;
/* The extra 2px are added to size solids the same as the outline versions.*/
padding: calc(0.667em + 2px) calc(1.333em + 2px);
font-size: 1.125em;
}
.wp-block-file__button {
background: #32373c;
color: #ffffff;
text-decoration: none;
}
/*! This file is auto-generated */
html{--wp-admin--admin-bar--height:32px;scroll-padding-top:var(--wp-admin--admin-bar--height)}#wpadminbar *{height:auto;width:auto;margin:0;padding:0;position:static;text-shadow:none;text-transform:none;letter-spacing:normal;font-size:13px;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-style:normal;line-height:2.46153846;border-radius:0;box-sizing:content-box;transition:none;-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto}.rtl #wpadminbar *{font-family:Tahoma,sans-serif}html:lang(he-il) .rtl #wpadminbar *{font-family:Arial,sans-serif}#wpadminbar .ab-empty-item{cursor:default}#wpadminbar .ab-empty-item,#wpadminbar a.ab-item,#wpadminbar>#wp-toolbar span.ab-label,#wpadminbar>#wp-toolbar span.noticon{color:#f0f0f1}#wpadminbar #wp-admin-bar-my-sites a.ab-item,#wpadminbar #wp-admin-bar-site-name a.ab-item{white-space:nowrap}#wpadminbar ul li:after,#wpadminbar ul li:before{content:normal}#wpadminbar a,#wpadminbar a img,#wpadminbar a img:hover,#wpadminbar a:hover{border:none;text-decoration:none;background:0 0;box-shadow:none}#wpadminbar a:active,#wpadminbar a:focus,#wpadminbar div,#wpadminbar input[type=email],#wpadminbar input[type=number],#wpadminbar input[type=password],#wpadminbar input[type=search],#wpadminbar input[type=text],#wpadminbar input[type=url],#wpadminbar select,#wpadminbar textarea{box-shadow:none}#wpadminbar a:focus{outline-offset:-1px}#wpadminbar{direction:rtl;color:#c3c4c7;font-size:13px;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;line-height:2.46153846;height:32px;position:fixed;top:0;right:0;width:100%;min-width:600px;z-index:99999;background:#1d2327;outline:1px solid transparent}#wpadminbar .ab-sub-wrapper,#wpadminbar ul,#wpadminbar ul li{background:0 0;clear:none;list-style:none;margin:0;padding:0;position:relative;text-indent:0;z-index:99999}#wpadminbar ul#wp-admin-bar-root-default>li{margin-left:0}#wpadminbar .quicklinks ul{text-align:right}#wpadminbar li{float:right}#wpadminbar .ab-empty-item{outline:0}#wpadminbar .quicklinks .ab-empty-item,#wpadminbar .quicklinks a,#wpadminbar .shortlink-input{height:32px;display:block;padding:0 10px;margin:0}#wpadminbar .quicklinks>ul>li>a{padding:0 7px 0 8px}#wpadminbar .menupop .ab-sub-wrapper,#wpadminbar .shortlink-input{margin:0;padding:0;box-shadow:0 3px 5px rgba(0,0,0,.2);background:#2c3338;display:none;position:absolute;float:none}#wpadminbar .ab-top-menu>.menupop>.ab-sub-wrapper{min-width:100%}#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper{left:0;right:auto}#wpadminbar .ab-submenu{padding:6px 0}#wpadminbar .selected .shortlink-input{display:block}#wpadminbar .quicklinks .menupop ul li{float:none}#wpadminbar .quicklinks .menupop ul li a strong{font-weight:600}#wpadminbar .quicklinks .menupop ul li .ab-item,#wpadminbar .quicklinks .menupop ul li a strong,#wpadminbar .quicklinks .menupop.hover ul li .ab-item,#wpadminbar .shortlink-input,#wpadminbar.nojs .quicklinks .menupop:hover ul li .ab-item{line-height:2;height:26px;white-space:nowrap;min-width:140px}#wpadminbar .shortlink-input{width:200px}#wpadminbar li.hover>.ab-sub-wrapper,#wpadminbar.nojs li:hover>.ab-sub-wrapper{display:block;outline:1px solid transparent}#wpadminbar .menupop li.hover>.ab-sub-wrapper,#wpadminbar .menupop li:hover>.ab-sub-wrapper{margin-right:100%;margin-top:-32px}#wpadminbar .ab-top-secondary .menupop li.hover>.ab-sub-wrapper,#wpadminbar .ab-top-secondary .menupop li:hover>.ab-sub-wrapper{margin-right:0;right:inherit;left:100%}#wpadminbar .ab-top-menu>li.hover>.ab-item,#wpadminbar.nojq .quicklinks .ab-top-menu>li>.ab-item:focus,#wpadminbar:not(.mobile) .ab-top-menu>li:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li>.ab-item:focus{background:#2c3338;color:#72aee6}#wpadminbar:not(.mobile)>#wp-toolbar a:focus span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li:hover span.ab-label,#wpadminbar>#wp-toolbar li.hover span.ab-label{color:#72aee6}#wpadminbar .ab-icon,#wpadminbar .ab-item:before,#wpadminbar>#wp-toolbar>#wp-admin-bar-root-default .ab-icon,.wp-admin-bar-arrow{position:relative;float:right;font:normal 20px/1 dashicons;speak:never;padding:4px 0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-image:none!important;margin-left:6px}#wpadminbar #adminbarsearch:before,#wpadminbar .ab-icon:before,#wpadminbar .ab-item:before{color:#a7aaad;color:rgba(240,246,252,.6)}#wpadminbar #adminbarsearch:before,#wpadminbar .ab-icon:before,#wpadminbar .ab-item:before{position:relative;transition:color .1s ease-in-out}#wpadminbar .ab-label{display:inline-block;height:32px}#wpadminbar .ab-submenu .ab-item{color:#c3c4c7;color:rgba(240,246,252,.7)}#wpadminbar .quicklinks .menupop ul li a,#wpadminbar .quicklinks .menupop ul li a strong,#wpadminbar .quicklinks .menupop.hover ul li a,#wpadminbar.nojs .quicklinks .menupop:hover ul li a{color:#c3c4c7;color:rgba(240,246,252,.7)}#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a,#wpadminbar .quicklinks .menupop ul li a:focus,#wpadminbar .quicklinks .menupop ul li a:focus strong,#wpadminbar .quicklinks .menupop ul li a:hover,#wpadminbar .quicklinks .menupop ul li a:hover strong,#wpadminbar .quicklinks .menupop.hover ul li a:focus,#wpadminbar .quicklinks .menupop.hover ul li a:hover,#wpadminbar .quicklinks .menupop.hover ul li div[tabindex]:focus,#wpadminbar .quicklinks .menupop.hover ul li div[tabindex]:hover,#wpadminbar li #adminbarsearch.adminbar-focused:before,#wpadminbar li .ab-item:focus .ab-icon:before,#wpadminbar li .ab-item:focus:before,#wpadminbar li a:focus .ab-icon:before,#wpadminbar li.hover .ab-icon:before,#wpadminbar li.hover .ab-item:before,#wpadminbar li:hover #adminbarsearch:before,#wpadminbar li:hover .ab-icon:before,#wpadminbar li:hover .ab-item:before,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover{color:#72aee6}#wpadminbar.mobile .quicklinks .ab-icon:before,#wpadminbar.mobile .quicklinks .ab-item:before{color:#c3c4c7}#wpadminbar.mobile .quicklinks .hover .ab-icon:before,#wpadminbar.mobile .quicklinks .hover .ab-item:before{color:#72aee6}#wpadminbar .ab-top-secondary .menupop .menupop>.ab-item:before,#wpadminbar .menupop .menupop>.ab-item .wp-admin-bar-arrow:before{position:absolute;font:normal 17px/1 dashicons;speak:never;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#wpadminbar .menupop .menupop>.ab-item{display:block;padding-left:2em}#wpadminbar .menupop .menupop>.ab-item .wp-admin-bar-arrow:before{top:1px;left:10px;padding:4px 0;content:"\f141";color:inherit}#wpadminbar .ab-top-secondary .menupop .menupop>.ab-item{padding-right:2em;padding-left:1em}#wpadminbar .ab-top-secondary .menupop .menupop>.ab-item .wp-admin-bar-arrow:before{top:1px;right:6px;content:"\f139"}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary{display:block;position:relative;left:auto;margin:0;box-shadow:none}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu{background:#3c434a}#wpadminbar .quicklinks .menupop .ab-sub-secondary>li .ab-item:focus a,#wpadminbar .quicklinks .menupop .ab-sub-secondary>li>a:hover{color:#72aee6}#wpadminbar .quicklinks a span#ab-updates{background:#f0f0f1;color:#2c3338;display:inline;padding:2px 5px;font-size:10px;font-weight:600;border-radius:10px}#wpadminbar .quicklinks a:hover span#ab-updates{background:#fff;color:#000}#wpadminbar .ab-top-secondary{float:left}#wpadminbar ul li:last-child,#wpadminbar ul li:last-child .ab-item{box-shadow:none}#wpadminbar #wp-admin-bar-recovery-mode{color:#fff;background-color:#d63638}#wpadminbar .ab-top-menu>#wp-admin-bar-recovery-mode.hover>.ab-item,#wpadminbar.nojq .quicklinks .ab-top-menu>#wp-admin-bar-recovery-mode>.ab-item:focus,#wpadminbar:not(.mobile) .ab-top-menu>#wp-admin-bar-recovery-mode:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>#wp-admin-bar-recovery-mode>.ab-item:focus{color:#fff;background-color:#d63638}#wp-admin-bar-my-account>ul{min-width:198px}#wp-admin-bar-my-account:not(.with-avatar)>.ab-item{display:inline-block}#wp-admin-bar-my-account>.ab-item:before{content:"\f110";top:2px;float:left;margin-right:6px;margin-left:0}#wp-admin-bar-my-account.with-avatar>.ab-item:before{display:none;content:none}#wp-admin-bar-my-account.with-avatar>ul{min-width:270px}#wpadminbar #wp-admin-bar-user-actions>li{margin-right:16px;margin-left:16px}#wpadminbar #wp-admin-bar-user-actions.ab-submenu{padding:6px 0 12px}#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions>li{margin-right:88px}#wpadminbar #wp-admin-bar-user-info{margin-top:6px;margin-bottom:15px;height:auto;background:0 0}#wp-admin-bar-user-info .avatar{position:absolute;right:-72px;top:4px;width:64px;height:64px}#wpadminbar #wp-admin-bar-user-info a{background:0 0;height:auto}#wpadminbar #wp-admin-bar-user-info span{background:0 0;padding:0;height:18px}#wpadminbar #wp-admin-bar-user-info .display-name,#wpadminbar #wp-admin-bar-user-info .username{display:block}#wpadminbar #wp-admin-bar-user-info .username{color:#a7aaad;font-size:11px}#wpadminbar #wp-admin-bar-my-account.with-avatar>.ab-empty-item img,#wpadminbar #wp-admin-bar-my-account.with-avatar>a img{width:auto;height:16px;padding:0;border:1px solid #8c8f94;background:#f0f0f1;line-height:1.84615384;vertical-align:middle;margin:-4px 6px 0 0;float:none;display:inline}#wpadminbar #wp-admin-bar-wp-logo>.ab-item .ab-icon{width:15px;height:20px;margin-left:0;padding:6px 0 5px}#wpadminbar #wp-admin-bar-wp-logo>.ab-item{padding:0 7px}#wpadminbar #wp-admin-bar-wp-logo>.ab-item .ab-icon:before{content:"\f120";top:2px}#wpadminbar .quicklinks li .blavatar{display:inline-block;vertical-align:middle;font:normal 16px/1 dashicons!important;speak:never;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#f0f0f1}#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a .blavatar,#wpadminbar .quicklinks li a:focus .blavatar,#wpadminbar .quicklinks li a:hover .blavatar{color:#72aee6}#wpadminbar .quicklinks li div.blavatar:before,#wpadminbar .quicklinks li img.blavatar{height:16px;width:16px;margin:0 -2px 2px 8px}#wpadminbar .quicklinks li div.blavatar:before{content:"\f120";display:inline-block}#wpadminbar #wp-admin-bar-appearance{margin-top:-12px}#wpadminbar #wp-admin-bar-my-sites>.ab-item:before,#wpadminbar #wp-admin-bar-site-name>.ab-item:before{content:"\f541";top:2px}#wpadminbar #wp-admin-bar-site-editor>.ab-item:before{content:"\f100";top:2px}#wpadminbar #wp-admin-bar-customize>.ab-item:before{content:"\f540";top:2px}#wpadminbar #wp-admin-bar-edit>.ab-item:before{content:"\f464";top:2px}#wpadminbar #wp-admin-bar-site-name>.ab-item:before{content:"\f226"}.wp-admin #wpadminbar #wp-admin-bar-site-name>.ab-item:before{content:"\f102"}#wpadminbar #wp-admin-bar-comments .ab-icon{margin-left:6px}#wpadminbar #wp-admin-bar-comments .ab-icon:before{content:"\f101";top:3px}#wpadminbar #wp-admin-bar-comments .count-0{opacity:.5}#wpadminbar #wp-admin-bar-new-content .ab-icon:before{content:"\f132";top:4px}#wpadminbar #wp-admin-bar-updates .ab-icon:before{content:"\f463";top:2px}#wpadminbar #wp-admin-bar-updates.spin .ab-icon:before{display:inline-block;animation:rotation 2s infinite linear}@media (prefers-reduced-motion:reduce){#wpadminbar #wp-admin-bar-updates.spin .ab-icon:before{animation:none}}#wpadminbar #wp-admin-bar-search .ab-item{padding:0;background:0 0}#wpadminbar #adminbarsearch{position:relative;height:32px;padding:0 2px;z-index:1}#wpadminbar #adminbarsearch:before{position:absolute;top:6px;right:5px;z-index:20;font:normal 20px/1 dashicons!important;content:"\f179";speak:never;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#wpadminbar>#wp-toolbar>#wp-admin-bar-top-secondary>#wp-admin-bar-search #adminbarsearch input.adminbar-input{display:inline-block;float:none;position:relative;z-index:30;font-size:13px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;line-height:1.84615384;text-indent:0;height:24px;width:24px;max-width:none;padding:0 24px 0 3px;margin:0;color:#c3c4c7;background-color:rgba(255,255,255,0);border:none;outline:0;cursor:pointer;box-shadow:none;box-sizing:border-box;transition-duration:.4s;transition-property:width,background;transition-timing-function:ease}#wpadminbar>#wp-toolbar>#wp-admin-bar-top-secondary>#wp-admin-bar-search #adminbarsearch input.adminbar-input:focus{z-index:10;color:#000;width:200px;background-color:rgba(255,255,255,.9);cursor:text;border:0}#wpadminbar #adminbarsearch .adminbar-button{display:none}.customize-support #wpadminbar .hide-if-customize,.customize-support .hide-if-customize,.customize-support .wp-core-ui .hide-if-customize,.customize-support.wp-core-ui .hide-if-customize,.no-customize-support #wpadminbar .hide-if-no-customize,.no-customize-support .hide-if-no-customize,.no-customize-support .wp-core-ui .hide-if-no-customize,.no-customize-support.wp-core-ui .hide-if-no-customize{display:none}#wpadminbar .screen-reader-text,#wpadminbar .screen-reader-text span{border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}#wpadminbar .screen-reader-shortcut{position:absolute;top:-1000em;right:6px;height:auto;width:auto;display:block;font-size:14px;font-weight:600;padding:15px 23px 14px;background:#f0f0f1;color:#2271b1;z-index:100000;line-height:normal;text-decoration:none}#wpadminbar .screen-reader-shortcut:focus{top:7px;background:#f0f0f1;box-shadow:0 0 2px 2px rgba(0,0,0,.6)}@media screen and (max-width:782px){html{--wp-admin--admin-bar--height:46px}html #wpadminbar{height:46px;min-width:240px}#wpadminbar *{font-size:14px;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;line-height:2.28571428}#wpadminbar .quicklinks .ab-empty-item,#wpadminbar .quicklinks>ul>li>a{padding:0;height:46px;line-height:3.28571428;width:auto}#wpadminbar .ab-icon{font:40px/1 dashicons!important;margin:0;padding:0;width:52px;height:46px;text-align:center}#wpadminbar .ab-icon:before{text-align:center}#wpadminbar .ab-submenu{padding:0}#wpadminbar #wp-admin-bar-my-account a.ab-item,#wpadminbar #wp-admin-bar-my-sites a.ab-item,#wpadminbar #wp-admin-bar-site-name a.ab-item{text-overflow:clip}#wpadminbar .quicklinks .menupop ul li .ab-item,#wpadminbar .quicklinks .menupop ul li a strong,#wpadminbar .quicklinks .menupop.hover ul li .ab-item,#wpadminbar .shortlink-input,#wpadminbar.nojs .quicklinks .menupop:hover ul li .ab-item{line-height:1.6}#wpadminbar .ab-label{border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}#wpadminbar .menupop li.hover>.ab-sub-wrapper,#wpadminbar .menupop li:hover>.ab-sub-wrapper{margin-top:-46px}#wpadminbar .ab-top-menu .menupop .ab-sub-wrapper .menupop>.ab-item{padding-left:30px}#wpadminbar .menupop .menupop>.ab-item:before{top:10px;left:6px}#wpadminbar .ab-top-menu>.menupop>.ab-sub-wrapper .ab-item{font-size:16px;padding:8px 16px}#wpadminbar .ab-top-menu>.menupop>.ab-sub-wrapper a:empty{display:none}#wpadminbar #wp-admin-bar-wp-logo>.ab-item{padding:0}#wpadminbar #wp-admin-bar-wp-logo>.ab-item .ab-icon{padding:0;width:52px;height:46px;text-align:center;vertical-align:top}#wpadminbar #wp-admin-bar-wp-logo>.ab-item .ab-icon:before{font:28px/1 dashicons!important;top:-3px}#wpadminbar .ab-icon,#wpadminbar .ab-item:before{padding:0}#wpadminbar #wp-admin-bar-customize>.ab-item,#wpadminbar #wp-admin-bar-edit>.ab-item,#wpadminbar #wp-admin-bar-my-account>.ab-item,#wpadminbar #wp-admin-bar-my-sites>.ab-item,#wpadminbar #wp-admin-bar-site-editor>.ab-item,#wpadminbar #wp-admin-bar-site-name>.ab-item{text-indent:100%;white-space:nowrap;overflow:hidden;width:52px;padding:0;color:#a7aaad;position:relative}#wpadminbar .ab-icon,#wpadminbar .ab-item:before,#wpadminbar>#wp-toolbar>#wp-admin-bar-root-default .ab-icon{padding:0;margin-left:0}#wpadminbar #wp-admin-bar-customize>.ab-item:before,#wpadminbar #wp-admin-bar-edit>.ab-item:before,#wpadminbar #wp-admin-bar-my-account>.ab-item:before,#wpadminbar #wp-admin-bar-my-sites>.ab-item:before,#wpadminbar #wp-admin-bar-site-editor>.ab-item:before,#wpadminbar #wp-admin-bar-site-name>.ab-item:before{display:block;text-indent:0;font:normal 32px/1 dashicons;speak:never;top:7px;width:52px;text-align:center;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#wpadminbar #wp-admin-bar-appearance{margin-top:0}#wpadminbar .quicklinks li .blavatar:before{display:none}#wpadminbar #wp-admin-bar-search{display:none}#wpadminbar #wp-admin-bar-new-content .ab-icon:before{top:0;line-height:1.26;height:46px!important;text-align:center;width:52px;display:block}#wpadminbar #wp-admin-bar-updates{text-align:center}#wpadminbar #wp-admin-bar-updates .ab-icon:before{top:3px}#wpadminbar #wp-admin-bar-comments .ab-icon{margin:0}#wpadminbar #wp-admin-bar-comments .ab-icon:before{display:block;font-size:34px;height:46px;line-height:1.38235294;top:0}#wpadminbar #wp-admin-bar-my-account>a{position:relative;white-space:nowrap;text-indent:150%;width:28px;padding:0 10px;overflow:hidden}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar>a img{position:absolute;top:13px;left:10px;width:26px;height:26px}#wpadminbar #wp-admin-bar-user-actions.ab-submenu{padding:0}#wpadminbar #wp-admin-bar-user-actions.ab-submenu img.avatar{display:none}#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions>li{margin:0}#wpadminbar #wp-admin-bar-user-info .display-name{height:auto;font-size:16px;line-height:1.5;color:#f0f0f1}#wpadminbar #wp-admin-bar-user-info a{padding-top:4px}#wpadminbar #wp-admin-bar-user-info .username{line-height:.8!important;margin-bottom:-2px}#wp-toolbar>ul>li{display:none}#wpadminbar li#wp-admin-bar-comments,#wpadminbar li#wp-admin-bar-customize,#wpadminbar li#wp-admin-bar-edit,#wpadminbar li#wp-admin-bar-menu-toggle,#wpadminbar li#wp-admin-bar-my-account,#wpadminbar li#wp-admin-bar-my-sites,#wpadminbar li#wp-admin-bar-new-content,#wpadminbar li#wp-admin-bar-site-editor,#wpadminbar li#wp-admin-bar-site-name,#wpadminbar li#wp-admin-bar-updates,#wpadminbar li#wp-admin-bar-wp-logo{display:block}#wpadminbar li.hover ul li,#wpadminbar li:hover ul li,#wpadminbar li:hover ul li:hover ul li{display:list-item}#wpadminbar .ab-top-menu>.menupop>.ab-sub-wrapper{min-width:fit-content}#wpadminbar ul#wp-admin-bar-root-default>li{margin-left:0}#wpadminbar #wp-admin-bar-comments,#wpadminbar #wp-admin-bar-edit,#wpadminbar #wp-admin-bar-my-account,#wpadminbar #wp-admin-bar-my-sites,#wpadminbar #wp-admin-bar-new-content,#wpadminbar #wp-admin-bar-site-name,#wpadminbar #wp-admin-bar-updates,#wpadminbar #wp-admin-bar-wp-logo,#wpadminbar .ab-top-menu,#wpadminbar .ab-top-secondary{position:static}.network-admin #wpadminbar ul#wp-admin-bar-top-secondary>li#wp-admin-bar-my-account{margin-left:0}#wpadminbar .ab-top-secondary .menupop .menupop>.ab-item:before{top:10px;right:0}}@media screen and (max-width:600px){#wpadminbar{position:absolute}#wp-responsive-overlay{position:fixed;top:0;right:0;width:100%;height:100%;z-index:400}#wpadminbar .ab-top-menu>.menupop>.ab-sub-wrapper{width:100%;right:0}#wpadminbar .menupop .menupop>.ab-item:before{display:none}#wpadminbar #wp-admin-bar-wp-logo.menupop .ab-sub-wrapper{margin-right:0}#wpadminbar .ab-top-menu>.menupop li>.ab-sub-wrapper{margin:0;width:100%;top:auto;right:auto;position:relative}#wpadminbar .ab-top-menu>.menupop li>.ab-sub-wrapper .ab-item{font-size:16px;padding:6px 30px 19px 15px}#wpadminbar li:hover ul li ul li{display:list-item}#wpadminbar li#wp-admin-bar-updates,#wpadminbar li#wp-admin-bar-wp-logo{display:none}#wpadminbar .ab-top-menu>.menupop li>.ab-sub-wrapper{position:static;box-shadow:none}}@media screen and (max-width:400px){#wpadminbar li#wp-admin-bar-comments{display:none}}html, body {
padding: 0;
margin: 0;
}
body {
font-family: sans-serif;
}
/* Text meant only for screen readers */
.screen-reader-text {
border: 0;
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
/* Dashicons */
.dashicons {
display: inline-block;
width: 20px;
height: 20px;
background-color: transparent;
background-repeat: no-repeat;
background-size: 20px;
background-position: center;
transition: background .1s ease-in;
position: relative;
top: 5px;
}
.dashicons-no {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M15.55%2013.7l-2.19%202.06-3.42-3.65-3.64%203.43-2.06-2.18%203.64-3.43-3.42-3.64%202.18-2.06%203.43%203.64%203.64-3.42%202.05%202.18-3.64%203.43z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
}
.dashicons-admin-comments {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M5%202h9q.82%200%201.41.59T16%204v7q0%20.82-.59%201.41T14%2013h-2l-5%205v-5H5q-.82%200-1.41-.59T3%2011V4q0-.82.59-1.41T5%202z%27%20fill%3D%27%2382878c%27%2F%3E%3C%2Fsvg%3E");
}
.wp-embed-comments a:hover .dashicons-admin-comments {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M5%202h9q.82%200%201.41.59T16%204v7q0%20.82-.59%201.41T14%2013h-2l-5%205v-5H5q-.82%200-1.41-.59T3%2011V4q0-.82.59-1.41T5%202z%27%20fill%3D%27%230073aa%27%2F%3E%3C%2Fsvg%3E");
}
.dashicons-share {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.5%2012q1.24%200%202.12.88T17.5%2015t-.88%202.12-2.12.88-2.12-.88T11.5%2015q0-.34.09-.69l-4.38-2.3Q6.32%2013%205%2013q-1.24%200-2.12-.88T2%2010t.88-2.12T5%207q1.3%200%202.21.99l4.38-2.3q-.09-.35-.09-.69%200-1.24.88-2.12T14.5%202t2.12.88T17.5%205t-.88%202.12T14.5%208q-1.3%200-2.21-.99l-4.38%202.3Q8%209.66%208%2010t-.09.69l4.38%202.3q.89-.99%202.21-.99z%27%20fill%3D%27%2382878c%27%2F%3E%3C%2Fsvg%3E");
display: none;
}
.js .dashicons-share {
display: inline-block;
}
.wp-embed-share-dialog-open:hover .dashicons-share {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.5%2012q1.24%200%202.12.88T17.5%2015t-.88%202.12-2.12.88-2.12-.88T11.5%2015q0-.34.09-.69l-4.38-2.3Q6.32%2013%205%2013q-1.24%200-2.12-.88T2%2010t.88-2.12T5%207q1.3%200%202.21.99l4.38-2.3q-.09-.35-.09-.69%200-1.24.88-2.12T14.5%202t2.12.88T17.5%205t-.88%202.12T14.5%208q-1.3%200-2.21-.99l-4.38%202.3Q8%209.66%208%2010t-.09.69l4.38%202.3q.89-.99%202.21-.99z%27%20fill%3D%27%230073aa%27%2F%3E%3C%2Fsvg%3E");
}
.wp-embed {
padding: 25px;
font-size: 14px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
line-height: 1.5;
color: #8c8f94;
background: #fff;
border: 1px solid #dcdcde;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
/* Clearfix */
overflow: auto;
zoom: 1;
}
.wp-embed a {
color: #8c8f94;
text-decoration: none;
}
.wp-embed a:hover {
text-decoration: underline;
}
.wp-embed-featured-image {
margin-bottom: 20px;
}
.wp-embed-featured-image img {
width: 100%;
height: auto;
border: none;
}
.wp-embed-featured-image.square {
float: left;
max-width: 160px;
margin-right: 20px;
}
.wp-embed p {
margin: 0;
}
p.wp-embed-heading {
margin: 0 0 15px;
font-weight: 600;
font-size: 22px;
line-height: 1.3;
}
.wp-embed-heading a {
color: #2c3338;
}
.wp-embed .wp-embed-more {
color: #c3c4c7;
}
.wp-embed-footer {
display: table;
width: 100%;
margin-top: 30px;
}
.wp-embed-site-icon {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
height: 25px;
width: 25px;
border: 0;
}
.wp-embed-site-title {
font-weight: 600;
line-height: 1.78571428;
}
.wp-embed-site-title a {
position: relative;
display: inline-block;
padding-left: 35px;
}
.wp-embed-site-title,
.wp-embed-meta {
display: table-cell;
}
.wp-embed-meta {
text-align: right;
white-space: nowrap;
vertical-align: middle;
}
.wp-embed-comments,
.wp-embed-share {
display: inline;
}
.wp-embed-meta a:hover {
text-decoration: none;
color: #2271b1;
}
.wp-embed-comments a {
line-height: 1.78571428;
display: inline-block;
}
.wp-embed-comments + .wp-embed-share {
margin-left: 10px;
}
.wp-embed-share-dialog {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #1d2327;
background-color: rgba(0, 0, 0, 0.9);
color: #fff;
opacity: 1;
transition: opacity .25s ease-in-out;
}
.wp-embed-share-dialog.hidden {
opacity: 0;
visibility: hidden;
}
.wp-embed-share-dialog-open,
.wp-embed-share-dialog-close {
margin: -8px 0 0;
padding: 0;
background: transparent;
border: none;
cursor: pointer;
outline: none;
}
.wp-embed-share-dialog-open .dashicons,
.wp-embed-share-dialog-close .dashicons {
padding: 4px;
}
.wp-embed-share-dialog-open .dashicons {
top: 8px;
}
.wp-embed-share-dialog-open:focus .dashicons,
.wp-embed-share-dialog-close:focus .dashicons {
box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
border-radius: 100%;
}
.wp-embed-share-dialog-close {
position: absolute;
top: 20px;
right: 20px;
font-size: 22px;
}
.wp-embed-share-dialog-close:hover {
text-decoration: none;
}
.wp-embed-share-dialog-close .dashicons {
height: 24px;
width: 24px;
background-size: 24px;
}
.wp-embed-share-dialog-content {
height: 100%;
transform-style: preserve-3d;
overflow: hidden;
}
.wp-embed-share-dialog-text {
margin-top: 25px;
padding: 20px;
}
.wp-embed-share-tabs {
margin: 0 0 20px;
padding: 0;
list-style: none;
}
.wp-embed-share-tab-button {
display: inline-block;
}
.wp-embed-share-tab-button button {
margin: 0;
padding: 0;
border: none;
background: transparent;
font-size: 16px;
line-height: 1.3;
color: #a7aaad;
cursor: pointer;
transition: color .1s ease-in;
}
.wp-embed-share-tab-button [aria-selected="true"] {
color: #fff;
}
.wp-embed-share-tab-button button:hover {
color: #fff;
}
.wp-embed-share-tab-button + .wp-embed-share-tab-button {
margin: 0 0 0 10px;
padding: 0 0 0 11px;
border-left: 1px solid #a7aaad;
}
.wp-embed-share-tab[aria-hidden="true"] {
display: none;
}
p.wp-embed-share-description {
margin: 0;
font-size: 14px;
line-height: 1;
font-style: italic;
color: #a7aaad;
}
.wp-embed-share-input {
box-sizing: border-box;
width: 100%;
border: none;
height: 28px;
margin: 0 0 10px;
padding: 0 5px;
font-size: 14px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
line-height: 1.5;
resize: none;
cursor: text;
}
textarea.wp-embed-share-input {
height: 72px;
}
html[dir="rtl"] .wp-embed-featured-image.square {
float: right;
margin-right: 0;
margin-left: 20px;
}
html[dir="rtl"] .wp-embed-site-title a {
padding-left: 0;
padding-right: 35px;
}
html[dir="rtl"] .wp-embed-site-icon {
margin-right: 0;
margin-left: 10px;
left: auto;
right: 0;
}
html[dir="rtl"] .wp-embed-meta {
text-align: left;
}
html[dir="rtl"] .wp-embed-share {
margin-left: 0;
margin-right: 10px;
}
html[dir="rtl"] .wp-embed-share-dialog-close {
right: auto;
left: 20px;
}
html[dir="rtl"] .wp-embed-share-tab-button + .wp-embed-share-tab-button {
margin: 0 10px 0 0;
padding: 0 11px 0 0;
border-left: none;
border-right: 1px solid #a7aaad;
}
.dashicons-no {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAAAcElEQVR4AdXRVxmEMBAGwJMQCUhAIhKQECmRsFJwMFfp7HfP/E8pk0173CuKpt/0R+WaBaaZqogLagBMuh+DdoKbyRCwqZ/SnM0R5oQuZ2UHS8Z6k23qPxZCTrV5UlHMi8bsfHVXP7K/GXZHaTO7S54CWLdHlN2YIwAAAABJRU5ErkJggg==);
}
.dashicons-admin-comments {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAATUlEQVR4AWMYWqCpvUcAiA8A8X9iMFStAD4DG0AKScQNVDZw1MBRAwvIMLCA5jmFlCD4AMQGlOTtBgoNwzQQ3TCKDaTcMMxYN2AYVgAAYPKsEBxN0PIAAAAASUVORK5CYII=);
}
.wp-embed-comments a:hover .dashicons-admin-comments {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAATElEQVR4AWMYYqB4lQAQHwDi/8RgqFoBfAY2gBSSiBuobOCogaMGFpBhYAEdcwrhIPgAxAaU5O0GCg3DNBDdMIoNpNwwzFg3YBhWAABG71qAFYcFqgAAAABJRU5ErkJggg==);
}
.dashicons-share {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAc0lEQVR4AWMYfqCpvccAiBcA8X8gfgDEBZQaeAFkGBoOoMR1/7HgDeQa2ECZgQiDHID4AMwAor0MCmBoQP+HBnwAskFQdgBRkQJViGk7wiAHUr21AYdhDTA1dDOQHl6mPFLokmwoT9j0z3qUFw70L77oDwAiuzCIub1XpQAAAABJRU5ErkJggg==);
}
.wp-embed-share-dialog-open:hover .dashicons-share {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAc0lEQVR4AWMYhqB4lQEQLwDi/0D8AIgLKDXwAsgwNBxAiev+Y8EbyDWwgTIDEQY5APEBmAFEexkUwNCA/g8N+ABkg6DsAKIiBaoQ03aEQQ6kemsDDsMaYEroZiA9vEx5pNAl2VCesOmf9SgvHOhffNEfAAAMqPR5IEZH5wAAAABJRU5ErkJggg==);
}
/*! This file is auto-generated */
.wp-core-ui .button,.wp-core-ui .button-primary,.wp-core-ui .button-secondary{display:inline-block;text-decoration:none;font-size:13px;line-height:2.15384615;min-height:30px;margin:0;padding:0 10px;cursor:pointer;border-width:1px;border-style:solid;-webkit-appearance:none;border-radius:3px;white-space:nowrap;box-sizing:border-box}.wp-core-ui button::-moz-focus-inner,.wp-core-ui input[type=button]::-moz-focus-inner,.wp-core-ui input[type=reset]::-moz-focus-inner,.wp-core-ui input[type=submit]::-moz-focus-inner{border-width:0;border-style:none;padding:0}.wp-core-ui .button-group.button-large .button,.wp-core-ui .button.button-large{min-height:32px;line-height:2.30769231;padding:0 12px}.wp-core-ui .button-group.button-small .button,.wp-core-ui .button.button-small{min-height:26px;line-height:2.18181818;padding:0 8px;font-size:11px}.wp-core-ui .button-group.button-hero .button,.wp-core-ui .button.button-hero{font-size:14px;min-height:46px;line-height:3.14285714;padding:0 36px}.wp-core-ui .button.hidden{display:none}.wp-core-ui input[type=reset],.wp-core-ui input[type=reset]:active,.wp-core-ui input[type=reset]:focus,.wp-core-ui input[type=reset]:hover{background:0 0;border:none;box-shadow:none;padding:0 2px 1px;width:auto}.wp-core-ui .button,.wp-core-ui .button-secondary{color:#2271b1;border-color:#2271b1;background:#f6f7f7;vertical-align:top}.wp-core-ui p .button{vertical-align:baseline}.wp-core-ui .button-secondary:hover,.wp-core-ui .button.hover,.wp-core-ui .button:hover{background:#f0f0f1;border-color:#0a4b78;color:#0a4b78}.wp-core-ui .button-secondary:focus,.wp-core-ui .button.focus,.wp-core-ui .button:focus{background:#f6f7f7;border-color:#3582c4;color:#0a4b78;box-shadow:0 0 0 1px #3582c4;outline:2px solid transparent;outline-offset:0}.wp-core-ui .button-secondary:active,.wp-core-ui .button:active{background:#f6f7f7;border-color:#8c8f94;box-shadow:none}.wp-core-ui .button.active,.wp-core-ui .button.active:hover{background-color:#dcdcde;color:#135e96;border-color:#0a4b78;box-shadow:inset 0 2px 5px -3px #0a4b78}.wp-core-ui .button.active:focus{border-color:#3582c4;box-shadow:inset 0 2px 5px -3px #0a4b78,0 0 0 1px #3582c4}.wp-core-ui .button-disabled,.wp-core-ui .button-secondary.disabled,.wp-core-ui .button-secondary:disabled,.wp-core-ui .button-secondary[disabled],.wp-core-ui .button.disabled,.wp-core-ui .button:disabled,.wp-core-ui .button[disabled]{color:#a7aaad!important;border-color:#dcdcde!important;background:#f6f7f7!important;box-shadow:none!important;cursor:default;transform:none!important}.wp-core-ui .button-secondary[aria-disabled=true],.wp-core-ui .button[aria-disabled=true]{cursor:default}.wp-core-ui .button-link{margin:0;padding:0;box-shadow:none;border:0;border-radius:0;background:0 0;cursor:pointer;text-align:left;color:#2271b1;text-decoration:underline;transition-property:border,background,color;transition-duration:.05s;transition-timing-function:ease-in-out}.wp-core-ui .button-link:active,.wp-core-ui .button-link:hover{color:#135e96}.wp-core-ui .button-link:focus{color:#043959;box-shadow:0 0 0 2px #2271b1;outline:2px solid transparent}.wp-core-ui .button-link-delete{color:#d63638}.wp-core-ui .button-link-delete:focus,.wp-core-ui .button-link-delete:hover{color:#d63638;background:0 0}.wp-core-ui .button-link-delete:disabled{background:0 0!important}.wp-core-ui .button-primary{background:#2271b1;border-color:#2271b1;color:#fff;text-decoration:none;text-shadow:none}.wp-core-ui .button-primary.focus,.wp-core-ui .button-primary.hover,.wp-core-ui .button-primary:focus,.wp-core-ui .button-primary:hover{background:#135e96;border-color:#135e96;color:#fff}.wp-core-ui .button-primary.focus,.wp-core-ui .button-primary:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #2271b1}.wp-core-ui .button-primary.active,.wp-core-ui .button-primary.active:focus,.wp-core-ui .button-primary.active:hover,.wp-core-ui .button-primary:active{background:#135e96;border-color:#135e96;box-shadow:none;color:#fff}.wp-core-ui .button-primary-disabled,.wp-core-ui .button-primary.disabled,.wp-core-ui .button-primary:disabled,.wp-core-ui .button-primary[disabled]{color:#a7aaad!important;background:#f6f7f7!important;border-color:#dcdcde!important;box-shadow:none!important;text-shadow:none!important;cursor:default}.wp-core-ui .button-primary[aria-disabled=true]{cursor:default}.wp-core-ui .button-group{position:relative;display:inline-block;white-space:nowrap;font-size:0;vertical-align:middle}.wp-core-ui .button-group>.button{display:inline-block;border-radius:0;margin-right:-1px}.wp-core-ui .button-group>.button:first-child{border-radius:3px 0 0 3px}.wp-core-ui .button-group>.button:last-child{border-radius:0 3px 3px 0}.wp-core-ui .button-group>.button-primary+.button{border-left:0}.wp-core-ui .button-group>.button:focus{position:relative;z-index:1}.wp-core-ui .button-group>.button.active{background-color:#dcdcde;color:#135e96;border-color:#0a4b78;box-shadow:inset 0 2px 5px -3px #0a4b78}.wp-core-ui .button-group>.button.active:focus{border-color:#3582c4;box-shadow:inset 0 2px 5px -3px #0a4b78,0 0 0 1px #3582c4}@media screen and (max-width:782px){.wp-core-ui .button,.wp-core-ui .button.button-large,.wp-core-ui .button.button-small,a.preview,input#publish,input#save-post{padding:0 14px;line-height:2.71428571;font-size:14px;vertical-align:middle;min-height:40px;margin-bottom:4px}.wp-core-ui .copy-to-clipboard-container .copy-attachment-url{margin-bottom:0}#media-upload.wp-core-ui .button{padding:0 10px 1px;min-height:24px;line-height:22px;font-size:13px}.media-frame.mode-grid .bulk-select .button{margin-bottom:0}.wp-core-ui .save-post-status.button{position:relative;margin:0 14px 0 10px}.wp-core-ui.wp-customizer .button{font-size:13px;line-height:2.15384615;min-height:30px;margin:0;vertical-align:inherit}.wp-customizer .theme-overlay .theme-actions .button{margin-bottom:5px}.media-modal-content .media-toolbar-primary .media-button{margin-top:10px;margin-left:5px}.interim-login .button.button-large{min-height:30px;line-height:2;padding:0 12px 2px}}/*! This file is auto-generated */
.dashicons-no{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAAAcElEQVR4AdXRVxmEMBAGwJMQCUhAIhKQECmRsFJwMFfp7HfP/E8pk0173CuKpt/0R+WaBaaZqogLagBMuh+DdoKbyRCwqZ/SnM0R5oQuZ2UHS8Z6k23qPxZCTrV5UlHMi8bsfHVXP7K/GXZHaTO7S54CWLdHlN2YIwAAAABJRU5ErkJggg==)}.dashicons-admin-comments{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAATUlEQVR4AWMYWqCpvUcAiA8A8X9iMFStAD4DG0AKScQNVDZw1MBRAwvIMLCA5jmFlCD4AMQGlOTtBgoNwzQQ3TCKDaTcMMxYN2AYVgAAYPKsEBxN0PIAAAAASUVORK5CYII=)}.wp-embed-comments a:hover .dashicons-admin-comments{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAATElEQVR4AWMYYqB4lQAQHwDi/8RgqFoBfAY2gBSSiBuobOCogaMGFpBhYAEdcwrhIPgAxAaU5O0GCg3DNBDdMIoNpNwwzFg3YBhWAABG71qAFYcFqgAAAABJRU5ErkJggg==)}.dashicons-share{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAc0lEQVR4AWMYfqCpvccAiBcA8X8gfgDEBZQaeAFkGBoOoMR1/7HgDeQa2ECZgQiDHID4AMwAor0MCmBoQP+HBnwAskFQdgBRkQJViGk7wiAHUr21AYdhDTA1dDOQHl6mPFLokmwoT9j0z3qUFw70L77oDwAiuzCIub1XpQAAAABJRU5ErkJggg==)}.wp-embed-share-dialog-open:hover .dashicons-share{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAc0lEQVR4AWMYhqB4lQEQLwDi/0D8AIgLKDXwAsgwNBxAiev+Y8EbyDWwgTIDEQY5APEBmAFEexkUwNCA/g8N+ABkg6DsAKIiBaoQ03aEQQ6kemsDDsMaYEroZiA9vEx5pNAl2VCesOmf9SgvHOhffNEfAAAMqPR5IEZH5wAAAABJRU5ErkJggg==)}/*! This file is auto-generated */
/*------------------------------------------------------------------------------
Interim login dialog
------------------------------------------------------------------------------*/
#wp-auth-check-wrap.hidden {
display: none;
}
#wp-auth-check-wrap #wp-auth-check-bg {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: #000;
opacity: 0.7;
filter: alpha(opacity=70);
z-index: 1000010; /* needs to appear above .notification-dialog */
}
#wp-auth-check-wrap #wp-auth-check {
position: fixed;
right: 50%;
overflow: hidden;
top: 40px;
bottom: 20px;
max-height: 415px;
width: 380px;
margin: 0 -190px 0 0;
padding: 30px 0 0;
background-color: #f0f0f1;
z-index: 1000011; /* needs to appear above #wp-auth-check-bg */
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
}
@media screen and (max-width: 380px) {
#wp-auth-check-wrap #wp-auth-check {
right: 0;
width: 100%;
margin: 0;
}
}
#wp-auth-check-wrap.fallback #wp-auth-check {
max-height: 180px;
overflow: auto;
}
#wp-auth-check-wrap #wp-auth-check-form {
height: 100%;
position: relative;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#wp-auth-check-form.loading:before {
content: "";
display: block;
width: 20px;
height: 20px;
position: absolute;
right: 50%;
top: 50%;
margin: -10px -10px 0 0;
background: url(../images/spinner.gif) no-repeat center;
background-size: 20px 20px;
transform: translateZ(0);
}
@media print,
(min-resolution: 120dpi) {
#wp-auth-check-form.loading:before {
background-image: url(../images/spinner-2x.gif);
}
}
#wp-auth-check-wrap #wp-auth-check-form iframe {
height: 98%; /* Scrollbar fix */
width: 100%;
}
#wp-auth-check-wrap .wp-auth-check-close {
position: absolute;
top: 5px;
left: 5px;
height: 22px;
width: 22px;
color: #787c82;
text-decoration: none;
text-align: center;
}
#wp-auth-check-wrap .wp-auth-check-close:before {
content: "\f158";
font: normal 20px/22px dashicons;
speak: never;
-webkit-font-smoothing: antialiased !important;
-moz-osx-font-smoothing: grayscale;
}
#wp-auth-check-wrap .wp-auth-check-close:hover,
#wp-auth-check-wrap .wp-auth-check-close:focus {
color: #2271b1;
}
#wp-auth-check-wrap .wp-auth-fallback-expired {
outline: 0;
}
#wp-auth-check-wrap .wp-auth-fallback {
font-size: 14px;
line-height: 1.5;
padding: 0 25px;
display: none;
}
#wp-auth-check-wrap.fallback .wp-auth-fallback,
#wp-auth-check-wrap.fallback .wp-auth-check-close {
display: block;
}
.customize-partial-refreshing {
opacity: 0.25;
transition: opacity 0.25s;
cursor: progress;
}
/* Override highlight when refreshing */
.customize-partial-refreshing.widget-customizer-highlighted-widget {
box-shadow: none;
}
/* Make shortcut buttons essentially invisible */
.widget .customize-partial-edit-shortcut,
.customize-partial-edit-shortcut {
position: absolute;
float: left;
width: 1px; /* required to have a size to be focusable in Safari */
height: 1px;
padding: 0;
margin: -1px 0 0 -1px;
border: 0;
background: transparent;
color: transparent;
box-shadow: none;
outline: none;
z-index: 5;
}
/**
* Styles for the actual shortcut
*
* Note that some properties are overly verbose to prevent theme interference.
*/
.widget .customize-partial-edit-shortcut button,
.customize-partial-edit-shortcut button {
position: absolute;
left: -30px;
top: 2px;
color: #fff;
width: 30px;
height: 30px;
min-width: 30px;
min-height: 30px;
line-height: 1 !important;
font-size: 18px;
z-index: 5;
background: #3582c4 !important;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 2px 1px rgba(60, 67, 74, 0.15);
text-align: center;
cursor: pointer;
box-sizing: border-box;
padding: 3px;
animation-fill-mode: both;
animation-duration: .4s;
opacity: 0;
pointer-events: none;
text-shadow:
0 -1px 1px #135e96,
1px 0 1px #135e96,
0 1px 1px #135e96,
-1px 0 1px #135e96;
}
.wp-custom-header .customize-partial-edit-shortcut button {
left: 2px
}
.customize-partial-edit-shortcut button svg {
fill: #fff;
min-width: 20px;
min-height: 20px;
width: 20px;
height: 20px;
margin: auto;
}
.customize-partial-edit-shortcut button:hover {
background: #4f94d4 !important; /* matches primary buttons */
}
.customize-partial-edit-shortcut button:focus {
box-shadow: 0 0 0 2px #4f94d4;
}
body.customize-partial-edit-shortcuts-shown .customize-partial-edit-shortcut button {
animation-name: customize-partial-edit-shortcut-bounce-appear;
pointer-events: auto;
}
body.customize-partial-edit-shortcuts-hidden .customize-partial-edit-shortcut button {
animation-name: customize-partial-edit-shortcut-bounce-disappear;
pointer-events: none;
}
.page-sidebar-collapsed .customize-partial-edit-shortcut button,
.customize-partial-edit-shortcut-hidden .customize-partial-edit-shortcut button {
visibility: hidden;
}
@keyframes customize-partial-edit-shortcut-bounce-appear {
from, 20%, 40%, 60%, 80%, to {
animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
}
0% {
opacity: 0;
transform: scale3d(.3, .3, .3);
}
20% {
transform: scale3d(1.1, 1.1, 1.1);
}
40% {
transform: scale3d(.9, .9, .9);
}
60% {
opacity: 1;
transform: scale3d(1.03, 1.03, 1.03);
}
80% {
transform: scale3d(.97, .97, .97);
}
to {
opacity: 1;
transform: scale3d(1, 1, 1);
}
}
@keyframes customize-partial-edit-shortcut-bounce-disappear {
from, 20%, 40%, 60%, 80%, to {
animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
}
0% {
opacity: 1;
transform: scale3d(1, 1, 1);
}
20% {
transform: scale3d(.97, .97, .97);
}
40% {
opacity: 1;
transform: scale3d(1.03, 1.03, 1.03);
}
60% {
transform: scale3d(.9, .9, .9);
}
80% {
transform: scale3d(1.1, 1.1, 1.1);
}
to {
opacity: 0;
transform: scale3d(.3, .3, .3);
}
}
@media screen and (max-width: 800px) {
.widget .customize-partial-edit-shortcut button,
.customize-partial-edit-shortcut button {
left: -32px;
}
}
@media screen and (max-width: 320px) {
.widget .customize-partial-edit-shortcut button,
.customize-partial-edit-shortcut button {
left: -30px;
}
}
/*! This file is auto-generated */
/*!
* jQuery UI CSS Framework 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:after,.ui-helper-clearfix:before{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;right:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;right:0;width:100%;height:100%}/*!
* jQuery UI Resizable 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;display:block;touch-action:none}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;right:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;right:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-button{display:inline-block;text-decoration:none;font-size:13px;line-height:2;height:28px;margin:0;padding:0 10px 1px;cursor:pointer;border-width:1px;border-style:solid;-webkit-appearance:none;border-radius:3px;white-space:nowrap;box-sizing:border-box;color:#50575e;border-color:#c3c4c7;background:#f6f7f7;box-shadow:0 1px 0 #c3c4c7;vertical-align:top}.ui-button:active,.ui-button:focus{outline:0}.ui-button::-moz-focus-inner{border-width:0;border-style:none;padding:0}.ui-button:focus,.ui-button:hover{background:#f6f7f7;border-color:#8c8f94;color:#1d2327}.ui-button:focus{border-color:#4f94d4;box-shadow:0 0 3px rgba(34,113,177,.8)}.ui-button:active{background:#f0f0f1;border-color:#8c8f94;box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.ui-button:disabled,.ui-button[disabled]{color:#a7aaad!important;border-color:#dcdcde!important;background:#f6f7f7!important;box-shadow:none!important;text-shadow:0 1px 0 #fff!important;cursor:default;transform:none!important}@media screen and (max-width:782px){.ui-button{padding:6px 14px;line-height:normal;font-size:14px;vertical-align:middle;height:auto;margin-bottom:4px}}.ui-dialog{position:absolute;top:0;right:0;z-index:100102;background-color:#fff;box-shadow:0 3px 6px rgba(0,0,0,.3);overflow:hidden}.ui-dialog-titlebar{background:#fff;border-bottom:1px solid #dcdcde;height:36px;font-size:18px;font-weight:600;line-height:2;padding:0 16px 0 36px}.ui-button.ui-dialog-titlebar-close{background:0 0;border:none;box-shadow:none;color:#646970;cursor:pointer;display:block;padding:0;position:absolute;top:0;left:0;width:36px;height:36px;text-align:center;border-radius:0;overflow:hidden}.ui-dialog-titlebar-close:before{font:normal 20px/1 dashicons;vertical-align:top;speak:never;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;line-height:1.8;width:36px;height:36px;content:"\f158"}.ui-button.ui-dialog-titlebar-close:focus,.ui-button.ui-dialog-titlebar-close:hover{color:#135e96}.ui-button.ui-dialog-titlebar-close:focus{box-shadow:0 0 0 2px #2271b1;outline:2px solid transparent;outline-offset:-2px}.ui-dialog-content{padding:16px;overflow:auto}.ui-dialog-buttonpane{background:#fff;border-top:1px solid #dcdcde;padding:16px}.ui-dialog-buttonpane .ui-button{margin-right:16px}.ui-dialog-buttonpane .ui-dialog-buttonset{float:left}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-widget-overlay{position:fixed;top:0;right:0;left:0;bottom:0;min-height:360px;background:#000;opacity:.7;z-index:100101}@charset "UTF-8";
:root{
--wp-admin-theme-color:#3858e9;
--wp-admin-theme-color--rgb:56, 88, 233;
--wp-admin-theme-color-darker-10:#2145e6;
--wp-admin-theme-color-darker-10--rgb:33, 69, 230;
--wp-admin-theme-color-darker-20:#183ad6;
--wp-admin-theme-color-darker-20--rgb:24, 58, 214;
--wp-admin-border-width-focus:2px;
}
@media (min-resolution:192dpi){
:root{
--wp-admin-border-width-focus:1.5px;
}
}
@media not (prefers-reduced-motion){
.components-animate__appear{
animation:components-animate__appear-animation .1s cubic-bezier(0, 0, .2, 1) 0s;
animation-fill-mode:forwards;
}
}
.components-animate__appear.is-from-top,.components-animate__appear.is-from-top.is-from-left{
transform-origin:top right;
}
.components-animate__appear.is-from-top.is-from-right{
transform-origin:top left;
}
.components-animate__appear.is-from-bottom,.components-animate__appear.is-from-bottom.is-from-left{
transform-origin:bottom right;
}
.components-animate__appear.is-from-bottom.is-from-right{
transform-origin:bottom left;
}
@keyframes components-animate__appear-animation{
0%{
transform:translateY(-2em) scaleY(0) scaleX(0);
}
to{
transform:translateY(0) scaleY(1) scaleX(1);
}
}
@media not (prefers-reduced-motion){
.components-animate__slide-in{
animation:components-animate__slide-in-animation .1s cubic-bezier(0, 0, .2, 1);
animation-fill-mode:forwards;
}
.components-animate__slide-in.is-from-left{
transform:translateX(-100%);
}
.components-animate__slide-in.is-from-right{
transform:translateX(100%);
}
}
@keyframes components-animate__slide-in-animation{
to{
transform:translateX(0);
}
}
@media not (prefers-reduced-motion){
.components-animate__loading{
animation:components-animate__loading 1.6s ease-in-out infinite;
}
}
@keyframes components-animate__loading{
0%{
opacity:.5;
}
50%{
opacity:1;
}
to{
opacity:.5;
}
}
.components-autocomplete__popover .components-popover__content{
min-width:200px;
padding:8px;
}
.components-autocomplete__result.components-button{
display:flex;
height:auto;
min-height:36px;
text-align:right;
width:100%;
}
.components-autocomplete__result.components-button:focus:not(:disabled){
box-shadow:inset 0 0 0 1px #fff, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-badge{
align-items:center;
background-color:color-mix(in srgb, #fff 90%, var(--base-color));
border-radius:2px;
box-sizing:border-box;
color:color-mix(in srgb, #000 50%, var(--base-color));
display:inline-flex;
font-size:12px;
font-weight:400;
gap:2px;
line-height:20px;
max-width:100%;
min-height:24px;
padding:0 8px;
}
.components-badge *,.components-badge :after,.components-badge :before{
box-sizing:inherit;
}
.components-badge:where(.is-default){
background-color:#f0f0f0;
color:#2f2f2f;
}
.components-badge.has-icon{
padding-inline-start:4px;
}
.components-badge.is-info{
--base-color:#3858e9;
}
.components-badge.is-warning{
--base-color:#f0b849;
}
.components-badge.is-error{
--base-color:#cc1818;
}
.components-badge.is-success{
--base-color:#4ab866;
}
.components-badge__icon{
flex-shrink:0;
}
.components-badge__content{
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.components-button-group{
display:inline-block;
}
.components-button-group .components-button{
border-radius:0;
box-shadow:inset 0 0 0 1px #1e1e1e;
color:#1e1e1e;
display:inline-flex;
}
.components-button-group .components-button+.components-button{
margin-right:-1px;
}
.components-button-group .components-button:first-child{
border-radius:0 2px 2px 0;
}
.components-button-group .components-button:last-child{
border-radius:2px 0 0 2px;
}
.components-button-group .components-button.is-primary,.components-button-group .components-button:focus{
position:relative;
z-index:1;
}
.components-button-group .components-button.is-primary{
box-shadow:inset 0 0 0 1px #1e1e1e;
}
.components-button{
align-items:center;
-webkit-appearance:none;
background:none;
border:0;
border-radius:2px;
box-sizing:border-box;
color:var(--wp-components-color-foreground, #1e1e1e);
cursor:pointer;
display:inline-flex;
font-family:inherit;
font-size:13px;
height:36px;
margin:0;
padding:6px 12px;
text-decoration:none;
}
@media not (prefers-reduced-motion){
.components-button{
transition:box-shadow .1s linear;
}
}
.components-button.is-next-40px-default-size{
height:40px;
}
.components-button:hover:not(:disabled,[aria-disabled=true]),.components-button[aria-expanded=true]{
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button:focus:not(:disabled){
box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:3px solid #0000;
}
.components-button.is-primary{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:var(--wp-components-color-accent-inverted, #fff);
outline:1px solid #0000;
text-decoration:none;
text-shadow:none;
white-space:nowrap;
}
.components-button.is-primary:hover:not(:disabled){
background:var(--wp-components-color-accent-darker-10, var(--wp-admin-theme-color-darker-10, #2145e6));
color:var(--wp-components-color-accent-inverted, #fff);
}
.components-button.is-primary:active:not(:disabled){
background:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
border-color:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
color:var(--wp-components-color-accent-inverted, #fff);
}
.components-button.is-primary:focus:not(:disabled){
box-shadow:inset 0 0 0 1px var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button.is-primary:disabled,.components-button.is-primary:disabled:active:enabled,.components-button.is-primary[aria-disabled=true],.components-button.is-primary[aria-disabled=true]:active:enabled,.components-button.is-primary[aria-disabled=true]:enabled{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:#fff6;
outline:none;
}
.components-button.is-primary:disabled:active:enabled:focus:enabled,.components-button.is-primary:disabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:active:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:focus:enabled{
box-shadow:inset 0 0 0 1px var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button.is-primary.is-busy,.components-button.is-primary.is-busy:disabled,.components-button.is-primary.is-busy[aria-disabled=true]{
background-image:linear-gradient(45deg, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 33%, var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6)) 33%, var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6)) 70%, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 70%);
background-size:100px 100%;
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:var(--wp-components-color-accent-inverted, #fff);
}
.components-button.is-secondary,.components-button.is-tertiary{
outline:1px solid #0000;
}
.components-button.is-secondary:active:not(:disabled),.components-button.is-tertiary:active:not(:disabled){
box-shadow:none;
}
.components-button.is-secondary:disabled,.components-button.is-secondary[aria-disabled=true],.components-button.is-secondary[aria-disabled=true]:hover,.components-button.is-tertiary:disabled,.components-button.is-tertiary[aria-disabled=true],.components-button.is-tertiary[aria-disabled=true]:hover{
background:#0000;
color:#949494;
transform:none;
}
.components-button.is-secondary{
background:#0000;
box-shadow:inset 0 0 0 1px var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)), 0 0 0 currentColor;
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:1px solid #0000;
white-space:nowrap;
}
.components-button.is-secondary:hover:not(:disabled,[aria-disabled=true],.is-pressed){
background:color-mix(in srgb, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 4%, #0000);
box-shadow:inset 0 0 0 1px var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
color:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
}
.components-button.is-secondary:disabled:not(:focus),.components-button.is-secondary[aria-disabled=true]:hover:not(:focus),.components-button.is-secondary[aria-disabled=true]:not(:focus){
box-shadow:inset 0 0 0 1px #ddd;
}
.components-button.is-secondary:focus:not(:disabled){
box-shadow:0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button.is-tertiary{
background:#0000;
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
white-space:nowrap;
}
.components-button.is-tertiary:hover:not(:disabled,[aria-disabled=true],.is-pressed){
background:color-mix(in srgb, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 4%, #0000);
color:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
}
.components-button.is-tertiary:active:not(:disabled,[aria-disabled=true]){
background:color-mix(in srgb, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 8%, #0000);
}
p+.components-button.is-tertiary{
margin-right:-6px;
}
.components-button.is-tertiary:disabled:not(:focus),.components-button.is-tertiary[aria-disabled=true]:hover:not(:focus),.components-button.is-tertiary[aria-disabled=true]:not(:focus){
box-shadow:none;
outline:none;
}
.components-button.is-destructive{
--wp-components-color-accent:#cc1818;
--wp-components-color-accent-darker-10:#9e1313;
--wp-components-color-accent-darker-20:#710d0d;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link){
color:#cc1818;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):hover:not(:disabled,[aria-disabled=true]){
color:#710d0d;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):focus{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #cc1818;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):active:not(:disabled,[aria-disabled=true]){
background:#ccc;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):disabled,.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link)[aria-disabled=true]{
color:#949494;
}
.components-button.is-destructive.is-secondary:hover:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:hover:not(:disabled,[aria-disabled=true]){
background:#cc18180a;
}
.components-button.is-destructive.is-secondary:active:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:active:not(:disabled,[aria-disabled=true]){
background:#cc181814;
}
.components-button.is-link{
background:none;
border:0;
border-radius:0;
box-shadow:none;
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
height:auto;
margin:0;
outline:none;
padding:0;
text-align:right;
text-decoration:underline;
}
@media not (prefers-reduced-motion){
.components-button.is-link{
transition-duration:.05s;
transition-property:border, background, color;
transition-timing-function:ease-in-out;
}
}
.components-button.is-link:focus{
border-radius:2px;
}
.components-button.is-link:disabled,.components-button.is-link[aria-disabled=true]{
color:#949494;
}
.components-button:not(:disabled,[aria-disabled=true]):active{
color:var(--wp-components-color-foreground, #1e1e1e);
}
.components-button:disabled,.components-button[aria-disabled=true]{
color:#949494;
cursor:default;
}
.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{
background-image:linear-gradient(45deg, #fafafa 33%, #e0e0e0 0, #e0e0e0 70%, #fafafa 0);
background-size:100px 100%;
}
@media not (prefers-reduced-motion){
.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{
animation:components-button__busy-animation 2.5s linear infinite;
}
}
.components-button.is-compact{
height:32px;
}
.components-button.is-compact.has-icon:not(.has-text){
min-width:32px;
padding:0;
width:32px;
}
.components-button.is-small{
font-size:11px;
height:24px;
line-height:22px;
padding:0 8px;
}
.components-button.is-small.has-icon:not(.has-text){
min-width:24px;
padding:0;
width:24px;
}
.components-button.has-icon{
justify-content:center;
min-width:36px;
padding:6px;
}
.components-button.has-icon.is-next-40px-default-size{
min-width:40px;
}
.components-button.has-icon .dashicon{
align-items:center;
box-sizing:initial;
display:inline-flex;
justify-content:center;
padding:2px;
}
.components-button.has-icon.has-text{
gap:4px;
justify-content:start;
padding-left:12px;
padding-right:8px;
}
.components-button.is-pressed,.components-button.is-pressed:hover{
color:var(--wp-components-color-foreground-inverted, #fff);
}
.components-button.is-pressed:hover:not(:disabled,[aria-disabled=true]),.components-button.is-pressed:not(:disabled,[aria-disabled=true]){
background:var(--wp-components-color-foreground, #1e1e1e);
}
.components-button.is-pressed:disabled,.components-button.is-pressed[aria-disabled=true]{
color:#949494;
}
.components-button.is-pressed:disabled:not(.is-primary):not(.is-secondary):not(.is-tertiary),.components-button.is-pressed[aria-disabled=true]:not(.is-primary):not(.is-secondary):not(.is-tertiary){
background:#949494;
color:var(--wp-components-color-foreground-inverted, #fff);
}
.components-button.is-pressed:focus:not(:disabled){
box-shadow:inset 0 0 0 1px var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
}
.components-button svg{
fill:currentColor;
outline:none;
}
@media (forced-colors:active){
.components-button svg{
fill:CanvasText;
}
}
.components-button .components-visually-hidden{
height:auto;
}
@keyframes components-button__busy-animation{
0%{
background-position:right 200px top 0;
}
}
.components-checkbox-control{
--checkbox-input-size:24px;
--checkbox-input-margin:8px;
}
@media (min-width:600px){
.components-checkbox-control{
--checkbox-input-size:16px;
}
}
.components-checkbox-control__label{
cursor:pointer;
line-height:var(--checkbox-input-size);
}
.components-checkbox-control__input[type=checkbox]{
appearance:none;
background:#fff;
border:1px solid #1e1e1e;
border-radius:2px;
box-shadow:0 0 0 #0000;
clear:none;
color:#1e1e1e;
cursor:pointer;
display:inline-block;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
height:var(--checkbox-input-size);
line-height:normal;
line-height:0;
margin:0 0 0 4px;
outline:0;
padding:6px 8px;
padding:0 !important;
text-align:center;
transition:none;
vertical-align:top;
width:var(--checkbox-input-size);
}
@media not (prefers-reduced-motion){
.components-checkbox-control__input[type=checkbox]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-checkbox-control__input[type=checkbox]{
font-size:13px;
line-height:normal;
}
}
.components-checkbox-control__input[type=checkbox]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-checkbox-control__input[type=checkbox]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-checkbox-control__input[type=checkbox]:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-checkbox-control__input[type=checkbox]:focus{
box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox]:checked{
background:var(--wp-admin-theme-color);
border-color:var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox]:checked::-ms-check{
opacity:0;
}
.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
color:#fff;
margin:-3px -5px;
}
@media (min-width:782px){
.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
margin:-4px -5px 0 0;
}
}
.components-checkbox-control__input[type=checkbox][aria-checked=mixed]{
background:var(--wp-admin-theme-color);
border-color:var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
content:"\f460";
display:inline-block;
float:right;
font:normal 30px/1 dashicons;
vertical-align:middle;
width:16px;
speak:none;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
@media (min-width:782px){
.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
float:none;
font-size:21px;
}
}
.components-checkbox-control__input[type=checkbox]:disabled,.components-checkbox-control__input[type=checkbox][aria-disabled=true]{
background:#f0f0f0;
border-color:#ddd;
cursor:default;
opacity:1;
}
@media not (prefers-reduced-motion){
.components-checkbox-control__input[type=checkbox]{
transition:border-color .1s ease-in-out;
}
}
.components-checkbox-control__input[type=checkbox]:focus{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);
outline:2px solid #0000;
outline-offset:2px;
}
.components-checkbox-control__input[type=checkbox]:checked,.components-checkbox-control__input[type=checkbox]:indeterminate{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-checkbox-control__input[type=checkbox]:checked::-ms-check,.components-checkbox-control__input[type=checkbox]:indeterminate::-ms-check{
opacity:0;
}
.components-checkbox-control__input[type=checkbox]:checked:before{
content:none;
}
.components-checkbox-control__input-container{
aspect-ratio:1;
display:inline-block;
flex-shrink:0;
line-height:1;
margin-left:var(--checkbox-input-margin);
position:relative;
vertical-align:middle;
width:var(--checkbox-input-size);
}
svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{
--checkmark-size:var(--checkbox-input-size);
fill:#fff;
cursor:pointer;
height:var(--checkmark-size);
pointer-events:none;
position:absolute;
right:50%;
top:50%;
transform:translate(50%, -50%);
-webkit-user-select:none;
user-select:none;
width:var(--checkmark-size);
}
@media (min-width:600px){
svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{
--checkmark-size:calc(var(--checkbox-input-size) + 4px);
}
}
.components-checkbox-control__help{
display:inline-block;
margin-inline-start:calc(var(--checkbox-input-size) + var(--checkbox-input-margin));
}
.components-circular-option-picker{
display:inline-block;
min-width:188px;
width:100%;
}
.components-circular-option-picker .components-circular-option-picker__custom-clear-wrapper{
display:flex;
justify-content:flex-end;
margin-top:12px;
}
.components-circular-option-picker .components-circular-option-picker__swatches{
display:flex;
flex-wrap:wrap;
gap:12px;
position:relative;
z-index:1;
}
.components-circular-option-picker>:not(.components-circular-option-picker__swatches){
position:relative;
z-index:0;
}
.components-circular-option-picker__option-wrapper{
display:inline-block;
height:28px;
transform:scale(1);
vertical-align:top;
width:28px;
}
@media not (prefers-reduced-motion){
.components-circular-option-picker__option-wrapper{
transition:transform .1s ease;
will-change:transform;
}
}
.components-circular-option-picker__option-wrapper:hover{
transform:scale(1.2);
}
.components-circular-option-picker__option-wrapper>div{
height:100%;
width:100%;
}
.components-circular-option-picker__option-wrapper:before{
background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' fill='none'%3E%3Cpath fill='%23555D65' d='M6 8V6H4v2zm2 0V6h2v2zm2 8H8v-2h2zm2 0v-2h2v2zm0 2v-2h-2v2H8v2h2v-2zm2 0v2h-2v-2zm2 0h-2v-2h2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M18 18h2v-2h-2v-2h2v-2h-2v-2h2V8h-2v2h-2V8h-2v2h2v2h-2v2h2v2h2zm-2-4v-2h2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' d='M18 18v2h-2v-2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M8 10V8H6v2H4v2h2v2H4v2h2v2H4v2h2v2H4v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2v2h-2V4h-2v2h-2V4h-2v2h-2V4h-2v2h2v2h-2v2zm0 2v-2H6v2zm2 0v-2h2v2zm0 2v-2H8v2H6v2h2v2H6v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h-2v2h-2V6h-2v2h-2v2h2v2h-2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M4 0H2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2H8V0H6v2H4zm0 4V2H2v2zm2 0V2h2v2zm0 2V4H4v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2H8v2z' clip-rule='evenodd'/%3E%3C/svg%3E");
border-radius:50%;
bottom:1px;
content:"";
left:1px;
position:absolute;
right:1px;
top:1px;
z-index:-1;
}
.components-circular-option-picker__option{
aspect-ratio:1;
background:#0000;
border:none;
border-radius:50%;
box-shadow:inset 0 0 0 14px;
cursor:pointer;
display:inline-block;
height:100% !important;
vertical-align:top;
}
@media not (prefers-reduced-motion){
.components-circular-option-picker__option{
transition:box-shadow .1s ease;
}
}
.components-circular-option-picker__option:hover{
box-shadow:inset 0 0 0 14px !important;
}
.components-circular-option-picker__option[aria-pressed=true],.components-circular-option-picker__option[aria-selected=true]{
box-shadow:inset 0 0 0 4px;
overflow:visible;
position:relative;
z-index:1;
}
.components-circular-option-picker__option[aria-pressed=true]+svg,.components-circular-option-picker__option[aria-selected=true]+svg{
border-radius:50%;
pointer-events:none;
position:absolute;
right:2px;
top:2px;
z-index:2;
}
.components-circular-option-picker__option:after{
border:1px solid #0000;
border-radius:50%;
bottom:-1px;
box-shadow:inset 0 0 0 1px #0003;
box-sizing:inherit;
content:"";
left:-1px;
position:absolute;
right:-1px;
top:-1px;
}
.components-circular-option-picker__option:focus:after{
border:2px solid #757575;
border-radius:50%;
box-shadow:inset 0 0 0 2px #fff;
content:"";
height:calc(100% + 4px);
position:absolute;
right:50%;
top:50%;
transform:translate(50%, -50%);
width:calc(100% + 4px);
}
.components-circular-option-picker__option.components-button:focus{
background-color:initial;
box-shadow:inset 0 0 0 14px;
outline:none;
}
.components-circular-option-picker__button-action .components-circular-option-picker__option{
background:#fff;
color:#fff;
}
.components-circular-option-picker__dropdown-link-action{
margin-left:16px;
}
.components-circular-option-picker__dropdown-link-action .components-button{
line-height:22px;
}
.components-palette-edit__popover-gradient-picker{
padding:8px;
width:260px;
}
.components-dropdown-menu__menu .components-palette-edit__menu-button{
width:100%;
}
.component-color-indicator{
background:#fff linear-gradient(45deg, #0000 48%, #ddd 0, #ddd 52%, #0000 0);
border-radius:50%;
box-shadow:inset 0 0 0 1px #0003;
display:inline-block;
height:20px;
padding:0;
width:20px;
}
.components-combobox-control{
width:100%;
}
input.components-combobox-control__input[type=text]{
border:none;
box-shadow:none;
font-family:inherit;
font-size:16px;
line-height:inherit;
margin:0;
min-height:auto;
padding:2px;
width:100%;
}
@media (min-width:600px){
input.components-combobox-control__input[type=text]{
font-size:13px;
}
}
input.components-combobox-control__input[type=text]:focus{
box-shadow:none;
outline:none;
}
.components-combobox-control__suggestions-container{
align-items:flex-start;
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
display:flex;
flex-wrap:wrap;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
line-height:normal;
padding:0;
width:100%;
}
@media not (prefers-reduced-motion){
.components-combobox-control__suggestions-container{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-combobox-control__suggestions-container{
font-size:13px;
line-height:normal;
}
}
.components-combobox-control__suggestions-container:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-combobox-control__suggestions-container::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-combobox-control__suggestions-container::-moz-placeholder{
color:#1e1e1e9e;
}
.components-combobox-control__suggestions-container:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-combobox-control__suggestions-container:focus-within{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-combobox-control__suggestions-container .components-spinner{
margin:0;
}
.components-color-palette__custom-color-wrapper{
position:relative;
z-index:0;
}
.components-color-palette__custom-color-button{
background:none;
border:none;
border-radius:4px 4px 0 0;
box-shadow:inset 0 0 0 1px #0003;
box-sizing:border-box;
cursor:pointer;
height:64px;
outline:1px solid #0000;
position:relative;
width:100%;
}
.components-color-palette__custom-color-button:focus{
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline-width:2px;
}
.components-color-palette__custom-color-button:after{
background-image:repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0), repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0);
background-position:0 0, 24px 24px;
background-size:48px 48px;
border-radius:3px 3px 0 0;
content:"";
inset:1px;
position:absolute;
z-index:-1;
}
.components-color-palette__custom-color-text-wrapper{
border-radius:0 0 4px 4px;
box-shadow:inset 0 -1px 0 0 #0003,inset -1px 0 0 0 #0003,inset 1px 0 0 0 #0003;
font-size:13px;
padding:12px 16px;
position:relative;
}
.components-color-palette__custom-color-name{
color:var(--wp-components-color-foreground, #1e1e1e);
margin:0 1px;
}
.components-color-palette__custom-color-value{
color:#757575;
}
.components-color-palette__custom-color-value--is-hex{
text-transform:uppercase;
}
.components-color-palette__custom-color-value:empty:after{
content:"";
visibility:hidden;
}
.components-custom-gradient-picker__gradient-bar{
border-radius:2px;
height:48px;
position:relative;
width:100%;
z-index:1;
}
.components-custom-gradient-picker__gradient-bar.has-gradient{
background-image:repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0), repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0);
background-position:0 0, 12px 12px;
background-size:24px 24px;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__gradient-bar-background{
inset:0;
position:absolute;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__markers-container{
margin-left:auto;
margin-right:auto;
position:relative;
width:calc(100% - 48px);
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-dropdown{
display:flex;
height:16px;
position:absolute;
top:16px;
width:16px;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown{
background:#fff;
border-radius:50%;
color:#1e1e1e;
height:inherit;
min-width:16px !important;
padding:2px;
position:relative;
width:inherit;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown svg{
height:100%;
width:100%;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button{
border-radius:50%;
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 2px 0 #00000040;
height:inherit;
outline:2px solid #0000;
padding:0;
width:inherit;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button.is-active,.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button:focus{
box-shadow:inset 0 0 0 calc(var(--wp-admin-border-width-focus)*2) #fff, 0 0 2px 0 #00000040;
outline:1.5px solid #0000;
}
.components-custom-gradient-picker__remove-control-point-wrapper{
padding-bottom:8px;
}
.components-custom-gradient-picker__inserter{
direction:ltr;
}
.components-custom-gradient-picker__liner-gradient-indicator{
display:inline-block;
flex:0 auto;
height:20px;
width:20px;
}
.components-custom-gradient-picker__ui-line{
position:relative;
z-index:0;
}
.block-editor-dimension-control .components-base-control__field{
align-items:center;
display:flex;
}
.block-editor-dimension-control .components-base-control__label{
align-items:center;
display:flex;
margin-bottom:0;
margin-left:1em;
}
.block-editor-dimension-control .components-base-control__label .dashicon{
margin-left:.5em;
}
.block-editor-dimension-control.is-manual .components-base-control__label{
width:10em;
}
body.is-dragging-components-draggable{
cursor:move;
cursor:grabbing !important;
}
.components-draggable__invisible-drag-image{
height:50px;
position:fixed;
right:-1000px;
width:50px;
}
.components-draggable__clone{
background:#0000;
padding:0;
pointer-events:none;
position:fixed;
z-index:1000000000;
}
.components-drop-zone{
border-radius:2px;
bottom:0;
left:0;
opacity:0;
position:absolute;
right:0;
top:0;
visibility:hidden;
z-index:40;
}
.components-drop-zone.is-active{
opacity:1;
visibility:visible;
}
.components-drop-zone .components-drop-zone__content{
align-items:center;
background-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
bottom:0;
color:#fff;
display:flex;
height:100%;
justify-content:center;
left:0;
opacity:0;
pointer-events:none;
position:absolute;
right:0;
text-align:center;
top:0;
width:100%;
z-index:50;
}
.components-drop-zone .components-drop-zone__content-inner{
opacity:0;
transform:scale(.9);
}
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{
opacity:1;
}
@media not (prefers-reduced-motion){
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{
transition:opacity .2s ease-in-out;
}
}
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{
opacity:1;
transform:scale(1);
}
@media not (prefers-reduced-motion){
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{
transition:opacity .1s ease-in-out .1s,transform .1s ease-in-out .1s;
}
}
.components-drop-zone__content-icon,.components-drop-zone__content-text{
display:block;
}
.components-drop-zone__content-icon{
line-height:0;
margin:0 auto 8px;
fill:currentColor;
pointer-events:none;
}
.components-drop-zone__content-text{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
}
.components-dropdown{
display:inline-block;
}
.components-dropdown__content .components-popover__content{
padding:8px;
}
.components-dropdown__content .components-popover__content:has(.components-menu-group){
padding:0;
}
.components-dropdown__content .components-popover__content:has(.components-menu-group) .components-dropdown-menu__menu>.components-menu-item__button,.components-dropdown__content .components-popover__content:has(.components-menu-group)>.components-menu-item__button{
margin:8px;
width:auto;
}
.components-dropdown__content [role=menuitem]{
white-space:nowrap;
}
.components-dropdown__content .components-menu-group{
padding:8px;
}
.components-dropdown__content .components-menu-group+.components-menu-group{
border-top:1px solid #ccc;
padding:8px;
}
.components-dropdown__content.is-alternate .components-menu-group+.components-menu-group{
border-color:#1e1e1e;
}
.components-dropdown-menu__toggle{
vertical-align:top;
}
.components-dropdown-menu__menu{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
line-height:1.4;
width:100%;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item,.components-dropdown-menu__menu .components-menu-item{
cursor:pointer;
outline:none;
padding:6px;
white-space:nowrap;
width:100%;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator,.components-dropdown-menu__menu .components-menu-item.has-separator{
margin-top:6px;
overflow:visible;
position:relative;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator:before,.components-dropdown-menu__menu .components-menu-item.has-separator:before{
background-color:#ddd;
box-sizing:initial;
content:"";
display:block;
height:1px;
left:0;
position:absolute;
right:0;
top:-3px;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active svg,.components-dropdown-menu__menu .components-menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-menu-item.is-active svg{
background:#1e1e1e;
border-radius:1px;
box-shadow:0 0 0 1px #1e1e1e;
color:#fff;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-icon-only,.components-dropdown-menu__menu .components-menu-item.is-icon-only{
width:auto;
}
.components-dropdown-menu__menu .components-menu-item__button,.components-dropdown-menu__menu .components-menu-item__button.components-button{
height:auto;
min-height:40px;
padding-left:8px;
padding-right:8px;
text-align:right;
}
.components-duotone-picker__color-indicator:before{
background:#0000;
}
.components-duotone-picker__color-indicator>.components-button,.components-duotone-picker__color-indicator>.components-button.is-pressed:hover:not(:disabled){
background:linear-gradient(45deg, #0000 48%, #ddd 0, #ddd 52%, #0000 0);
color:#0000;
}
.components-duotone-picker__color-indicator>.components-button:not([aria-disabled=true]):active{
color:#0000;
}
.components-color-list-picker,.components-color-list-picker__swatch-button{
width:100%;
}
.components-color-list-picker__color-picker{
margin:8px 0;
}
.components-color-list-picker__swatch-color{
margin:2px;
}
.components-external-link{
text-decoration:none;
}
.components-external-link__contents{
text-decoration:underline;
}
.components-external-link__icon{
font-weight:400;
margin-right:.5ch;
}
.components-form-toggle,.components-form-toggle .components-form-toggle__track{
display:inline-block;
height:16px;
position:relative;
}
.components-form-toggle .components-form-toggle__track{
background-color:#fff;
border:1px solid #949494;
border-radius:8px;
box-sizing:border-box;
content:"";
overflow:hidden;
vertical-align:top;
width:32px;
}
@media not (prefers-reduced-motion){
.components-form-toggle .components-form-toggle__track{
transition:background-color .2s ease,border-color .2s ease;
}
}
.components-form-toggle .components-form-toggle__track:after{
border-top:16px solid #0000;
box-sizing:border-box;
content:"";
inset:0;
opacity:0;
position:absolute;
}
@media not (prefers-reduced-motion){
.components-form-toggle .components-form-toggle__track:after{
transition:opacity .2s ease;
}
}
.components-form-toggle .components-form-toggle__thumb{
background-color:#1e1e1e;
border:6px solid #0000;
border-radius:50%;
box-shadow:0 1px 1px #00000008,0 1px 2px #00000005,0 3px 3px #00000005,0 4px 4px #00000003;
box-sizing:border-box;
display:block;
height:12px;
position:absolute;
right:2px;
top:2px;
width:12px;
}
@media not (prefers-reduced-motion){
.components-form-toggle .components-form-toggle__thumb{
transition:transform .2s ease,background-color .2s ease-out;
}
}
.components-form-toggle.is-checked .components-form-toggle__track{
background-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-form-toggle.is-checked .components-form-toggle__track:after{
opacity:1;
}
.components-form-toggle .components-form-toggle__input:focus+.components-form-toggle__track{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
outline-offset:2px;
}
.components-form-toggle.is-checked .components-form-toggle__thumb{
background-color:#fff;
border-width:0;
transform:translateX(-16px);
}
.components-disabled .components-form-toggle,.components-form-toggle.is-disabled{
opacity:.3;
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]{
border:none;
height:100%;
margin:0;
opacity:0;
padding:0;
position:absolute;
right:0;
top:0;
width:100%;
z-index:1;
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]:checked{
background:none;
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]:before{
content:"";
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]:not(:disabled,[aria-disabled=true]){
cursor:pointer;
}
.components-form-token-field__input-container{
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
cursor:text;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
line-height:normal;
padding:0;
width:100%;
}
@media not (prefers-reduced-motion){
.components-form-token-field__input-container{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-form-token-field__input-container{
font-size:13px;
line-height:normal;
}
}
.components-form-token-field__input-container:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-form-token-field__input-container::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-form-token-field__input-container::-moz-placeholder{
color:#1e1e1e9e;
}
.components-form-token-field__input-container:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-form-token-field__input-container.is-disabled{
background:#ddd;
border-color:#ddd;
}
.components-form-token-field__input-container.is-active{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-form-token-field__input-container input[type=text].components-form-token-field__input{
background:inherit;
border:0;
box-shadow:none;
color:#1e1e1e;
display:inline-block;
flex:1;
font-family:inherit;
font-size:16px;
margin-right:4px;
max-width:100%;
min-height:24px;
min-width:50px;
padding:0;
width:100%;
}
@media (min-width:600px){
.components-form-token-field__input-container input[type=text].components-form-token-field__input{
font-size:13px;
}
}
.components-form-token-field.is-active .components-form-token-field__input-container input[type=text].components-form-token-field__input,.components-form-token-field__input-container input[type=text].components-form-token-field__input:focus{
box-shadow:none;
outline:none;
}
.components-form-token-field__input-container .components-form-token-field__token+input[type=text].components-form-token-field__input{
width:auto;
}
.components-form-token-field__token{
color:#1e1e1e;
display:flex;
font-size:13px;
max-width:100%;
}
.components-form-token-field__token.is-success .components-form-token-field__remove-token,.components-form-token-field__token.is-success .components-form-token-field__token-text{
background:#4ab866;
}
.components-form-token-field__token.is-error .components-form-token-field__remove-token,.components-form-token-field__token.is-error .components-form-token-field__token-text{
background:#cc1818;
}
.components-form-token-field__token.is-validating .components-form-token-field__remove-token,.components-form-token-field__token.is-validating .components-form-token-field__token-text{
color:#757575;
}
.components-form-token-field__token.is-borderless{
padding:0 0 0 24px;
position:relative;
}
.components-form-token-field__token.is-borderless .components-form-token-field__token-text{
background:#0000;
}
.components-form-token-field__token.is-borderless:not(.is-disabled) .components-form-token-field__token-text{
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-form-token-field__token.is-borderless .components-form-token-field__remove-token{
background:#0000;
color:#757575;
left:0;
position:absolute;
top:1px;
}
.components-form-token-field__token.is-borderless.is-success .components-form-token-field__token-text{
color:#4ab866;
}
.components-form-token-field__token.is-borderless.is-error .components-form-token-field__token-text{
color:#cc1818;
padding:0 6px 0 4px;
}
.components-form-token-field__token.is-borderless.is-validating .components-form-token-field__token-text{
color:#1e1e1e;
}
.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{
background:#ddd;
display:inline-block;
height:auto;
min-width:unset;
}
@media not (prefers-reduced-motion){
.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{
transition:all .2s cubic-bezier(.4, 1, .4, 1);
}
}
.components-form-token-field__token-text{
border-radius:0 1px 1px 0;
line-height:24px;
overflow:hidden;
padding:0 8px 0 0;
text-overflow:ellipsis;
white-space:nowrap;
}
.components-form-token-field__remove-token.components-button{
border-radius:1px 0 0 1px;
color:#1e1e1e;
line-height:10px;
overflow:initial;
}
.components-form-token-field__remove-token.components-button:hover:not(:disabled){
color:#1e1e1e;
}
.components-form-token-field__suggestions-list{
box-shadow:inset 0 1px 0 0 #949494;
flex:1 0 100%;
list-style:none;
margin:0;
max-height:128px;
min-width:100%;
overflow-y:auto;
padding:0;
}
@media not (prefers-reduced-motion){
.components-form-token-field__suggestions-list{
transition:all .15s ease-in-out;
}
}
.components-form-token-field__suggestion{
box-sizing:border-box;
color:#1e1e1e;
display:block;
font-size:13px;
margin:0;
min-height:32px;
padding:8px 12px;
}
.components-form-token-field__suggestion.is-selected{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:#fff;
}
.components-form-token-field__suggestion[aria-disabled=true]{
color:#949494;
pointer-events:none;
}
.components-form-token-field__suggestion[aria-disabled=true].is-selected{
background-color:rgba(var(--wp-components-color-accent--rgb, var(--wp-admin-theme-color--rgb)), .04);
}
.components-form-token-field__suggestion:not(.is-empty){
cursor:pointer;
}
@media (min-width:600px){
.components-guide{
width:600px;
}
}
.components-guide .components-modal__content{
margin-top:0;
padding:0;
}
.components-guide .components-modal__content:before{
content:none;
}
.components-guide .components-modal__header{
border-bottom:none;
height:60px;
padding:0;
position:sticky;
}
.components-guide .components-modal__header .components-button{
align-self:flex-start;
margin:8px 0 0 8px;
position:static;
}
.components-guide .components-modal__header .components-button:hover svg{
fill:#fff;
}
.components-guide .components-guide__container{
display:flex;
flex-direction:column;
justify-content:space-between;
margin-top:-60px;
min-height:100%;
}
.components-guide .components-guide__page{
display:flex;
flex-direction:column;
justify-content:center;
position:relative;
}
@media (min-width:600px){
.components-guide .components-guide__page{
min-height:300px;
}
}
.components-guide .components-guide__footer{
align-content:center;
display:flex;
height:36px;
justify-content:center;
margin:0 0 24px;
padding:0 32px;
position:relative;
width:100%;
}
.components-guide .components-guide__page-control{
margin:0;
text-align:center;
}
.components-guide .components-guide__page-control li{
display:inline-block;
margin:0;
}
.components-guide .components-guide__page-control .components-button{
color:#e0e0e0;
margin:-6px 0;
}
.components-guide .components-guide__page-control li[aria-current=step] .components-button{
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-modal__frame.components-guide{
border:none;
max-height:575px;
min-width:312px;
}
@media (max-width:600px){
.components-modal__frame.components-guide{
margin:auto;
max-width:calc(100vw - 32px);
}
}
.components-button.components-guide__back-button,.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{
position:absolute;
}
.components-button.components-guide__back-button{
right:32px;
}
.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{
left:32px;
}
[role=region]{
position:relative;
}
.is-focusing-regions [role=region]:focus:after,[role=region].interface-interface-skeleton__content:focus-visible:after{
bottom:0;
content:"";
left:0;
pointer-events:none;
position:absolute;
right:0;
top:0;
z-index:1000000;
}
.is-focusing-regions .editor-post-publish-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-entities-saved-states-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-publish-panel,.is-focusing-regions .interface-interface-skeleton__sidebar .editor-layout__toggle-sidebar-panel,.is-focusing-regions [role=region]:focus:after,.is-focusing-regions.is-distraction-free .interface-interface-skeleton__header .edit-post-header,[role=region].interface-interface-skeleton__content:focus-visible:after{
outline-color:var(--wp-admin-theme-color);
outline-offset:calc(((-1*var(--wp-admin-border-width-focus))/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2);
outline-style:solid;
outline-width:calc((var(--wp-admin-border-width-focus)/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2);
}
.components-menu-group+.components-menu-group{
border-top:1px solid #1e1e1e;
padding-top:8px;
}
.components-menu-group+.components-menu-group.has-hidden-separator{
border-top:none;
margin-top:0;
padding-top:0;
}
.components-menu-group:has(>div:empty){
display:none;
}
.components-menu-group__label{
color:#757575;
font-size:11px;
font-weight:500;
margin-bottom:12px;
margin-top:4px;
padding:0 8px;
text-transform:uppercase;
white-space:nowrap;
}
.components-menu-item__button,.components-menu-item__button.components-button{
width:100%;
}
.components-menu-item__button.components-button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button.components-button[role=menuitemradio] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemradio] .components-menu-item__item:only-child{
box-sizing:initial;
padding-left:48px;
}
.components-menu-item__button .components-menu-items__item-icon,.components-menu-item__button.components-button .components-menu-items__item-icon{
display:inline-block;
flex:0 0 auto;
}
.components-menu-item__button .components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-items__item-icon.has-icon-right{
margin-left:-2px;
margin-right:24px;
}
.components-menu-item__button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right{
margin-right:8px;
}
.components-menu-item__button .block-editor-block-icon,.components-menu-item__button.components-button .block-editor-block-icon{
margin-left:8px;
margin-right:-2px;
}
.components-menu-item__button.components-button.is-primary,.components-menu-item__button.is-primary{
justify-content:center;
}
.components-menu-item__button.components-button.is-primary .components-menu-item__item,.components-menu-item__button.is-primary .components-menu-item__item{
margin-left:0;
}
.components-menu-item__button.components-button:disabled.is-tertiary,.components-menu-item__button.components-button[aria-disabled=true].is-tertiary,.components-menu-item__button:disabled.is-tertiary,.components-menu-item__button[aria-disabled=true].is-tertiary{
background:none;
color:var(--wp-components-color-accent-darker-10, var(--wp-admin-theme-color-darker-10, #2145e6));
opacity:.3;
}
.components-menu-item__info-wrapper{
display:flex;
flex-direction:column;
margin-left:auto;
}
.components-menu-item__info{
color:#757575;
font-size:12px;
margin-top:4px;
white-space:normal;
}
.components-menu-item__item{
align-items:center;
display:inline-flex;
margin-left:auto;
min-width:160px;
white-space:nowrap;
}
.components-menu-item__shortcut{
align-self:center;
color:currentColor;
display:none;
margin-left:0;
margin-right:auto;
padding-right:24px;
}
@media (min-width:480px){
.components-menu-item__shortcut{
display:inline;
}
}
.components-menu-items-choice,.components-menu-items-choice.components-button{
height:auto;
min-height:40px;
}
.components-menu-items-choice svg,.components-menu-items-choice.components-button svg{
margin-left:12px;
}
.components-menu-items-choice.components-button.has-icon,.components-menu-items-choice.has-icon{
padding-right:12px;
}
.components-modal__screen-overlay{
background-color:#00000059;
bottom:0;
display:flex;
left:0;
position:fixed;
right:0;
top:0;
z-index:100000;
}
@keyframes __wp-base-styles-fade-in{
0%{
opacity:0;
}
to{
opacity:1;
}
}
@media not (prefers-reduced-motion){
.components-modal__screen-overlay{
animation:__wp-base-styles-fade-in .08s linear 0s;
animation-fill-mode:forwards;
}
}
@keyframes __wp-base-styles-fade-out{
0%{
opacity:1;
}
to{
opacity:0;
}
}
@media not (prefers-reduced-motion){
.components-modal__screen-overlay.is-animating-out{
animation:__wp-base-styles-fade-out .08s linear 80ms;
animation-fill-mode:forwards;
}
}
.components-modal__frame{
animation-fill-mode:forwards;
animation-name:components-modal__appear-animation;
animation-timing-function:cubic-bezier(.29, 0, 0, 1);
background:#fff;
border-radius:8px 8px 0 0;
box-shadow:0 5px 15px #00000014,0 15px 27px #00000012,0 30px 36px #0000000a,0 50px 43px #00000005;
box-sizing:border-box;
display:flex;
margin:40px 0 0;
overflow:hidden;
width:100%;
}
.components-modal__frame *,.components-modal__frame :after,.components-modal__frame :before{
box-sizing:inherit;
}
@media not (prefers-reduced-motion){
.components-modal__frame{
animation-duration:var(--modal-frame-animation-duration);
}
}
.components-modal__screen-overlay.is-animating-out .components-modal__frame{
animation-name:components-modal__disappear-animation;
animation-timing-function:cubic-bezier(1, 0, .2, 1);
}
@media (min-width:600px){
.components-modal__frame{
border-radius:8px;
margin:auto;
max-height:calc(100% - 120px);
max-width:calc(100% - 32px);
min-width:350px;
width:auto;
}
}
@media (min-width:600px) and (min-width:600px){
.components-modal__frame.is-full-screen{
height:calc(100% - 32px);
max-height:none;
width:calc(100% - 32px);
}
}
@media (min-width:600px) and (min-width:782px){
.components-modal__frame.is-full-screen{
height:calc(100% - 80px);
max-width:none;
width:calc(100% - 80px);
}
}
@media (min-width:600px){
.components-modal__frame.has-size-large,.components-modal__frame.has-size-medium,.components-modal__frame.has-size-small{
width:100%;
}
.components-modal__frame.has-size-small{
max-width:384px;
}
.components-modal__frame.has-size-medium{
max-width:512px;
}
.components-modal__frame.has-size-large{
max-width:840px;
}
}
@media (min-width:960px){
.components-modal__frame{
max-height:70%;
}
}
@keyframes components-modal__appear-animation{
0%{
opacity:0;
transform:scale(.9);
}
to{
opacity:1;
transform:scale(1);
}
}
@keyframes components-modal__disappear-animation{
0%{
opacity:1;
transform:scale(1);
}
to{
opacity:0;
transform:scale(.9);
}
}
.components-modal__header{
align-items:center;
border-bottom:1px solid #0000;
box-sizing:border-box;
display:flex;
flex-direction:row;
height:72px;
justify-content:space-between;
padding:24px 32px 8px;
position:absolute;
right:0;
top:0;
width:100%;
z-index:10;
}
.components-modal__header .components-modal__header-heading{
font-size:1.2rem;
font-weight:600;
}
.components-modal__header h1{
line-height:1;
margin:0;
}
.components-modal__content.has-scrolled-content:not(.hide-header) .components-modal__header{
border-bottom-color:#ddd;
}
.components-modal__header+p{
margin-top:0;
}
.components-modal__header-heading-container{
align-items:center;
display:flex;
flex-direction:row;
flex-grow:1;
justify-content:right;
}
.components-modal__header-icon-container{
display:inline-block;
}
.components-modal__header-icon-container svg{
max-height:36px;
max-width:36px;
padding:8px;
}
.components-modal__content{
flex:1;
margin-top:72px;
overflow:auto;
padding:4px 32px 32px;
}
.components-modal__content.hide-header{
margin-top:0;
padding-top:32px;
}
.components-modal__content.is-scrollable:focus-visible{
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
outline-offset:-2px;
}
.components-notice{
align-items:center;
background-color:#fff;
border-right:4px solid var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:#1e1e1e;
display:flex;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
padding:8px 12px;
}
.components-notice.is-dismissible{
position:relative;
}
.components-notice.is-success{
background-color:#eff9f1;
border-right-color:#4ab866;
}
.components-notice.is-warning{
background-color:#fef8ee;
border-right-color:#f0b849;
}
.components-notice.is-error{
background-color:#f4a2a2;
border-right-color:#cc1818;
}
.components-notice__content{
flex-grow:1;
margin:4px 0 4px 25px;
}
.components-notice__actions{
display:flex;
flex-wrap:wrap;
}
.components-notice__action.components-button{
margin-left:8px;
}
.components-notice__action.components-button,.components-notice__action.components-button.is-link{
margin-right:12px;
}
.components-notice__action.components-button.is-secondary{
vertical-align:initial;
}
.components-notice__dismiss{
align-self:flex-start;
color:#757575;
flex-shrink:0;
}
.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):focus,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):active,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{
background-color:initial;
color:#1e1e1e;
}
.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{
box-shadow:none;
}
.components-notice-list{
box-sizing:border-box;
max-width:100vw;
}
.components-notice-list .components-notice__content{
line-height:2;
margin-bottom:12px;
margin-top:12px;
}
.components-notice-list .components-notice__action.components-button{
display:block;
margin-right:0;
margin-top:8px;
}
.components-panel{
background:#fff;
border:1px solid #e0e0e0;
}
.components-panel>.components-panel__body:first-child,.components-panel>.components-panel__header:first-child{
margin-top:-1px;
}
.components-panel>.components-panel__body:last-child,.components-panel>.components-panel__header:last-child{
border-bottom-width:0;
}
.components-panel+.components-panel{
margin-top:-1px;
}
.components-panel__body{
border-bottom:1px solid #e0e0e0;
border-top:1px solid #e0e0e0;
}
.components-panel__body h3{
margin:0 0 .5em;
}
.components-panel__body.is-opened{
padding:16px;
}
.components-panel__header{
align-items:center;
border-bottom:1px solid #ddd;
box-sizing:initial;
display:flex;
flex-shrink:0;
height:47px;
justify-content:space-between;
padding:0 16px;
}
.components-panel__header h2{
color:inherit;
font-size:inherit;
margin:0;
}
.components-panel__body+.components-panel__body,.components-panel__body+.components-panel__header,.components-panel__header+.components-panel__body,.components-panel__header+.components-panel__header{
margin-top:-1px;
}
.components-panel__body>.components-panel__body-title{
display:block;
font-size:inherit;
margin-bottom:0;
margin-top:0;
padding:0;
}
@media not (prefers-reduced-motion){
.components-panel__body>.components-panel__body-title{
transition:background .1s ease-in-out;
}
}
.components-panel__body.is-opened>.components-panel__body-title{
margin:-16px -16px 5px;
}
.components-panel__body>.components-panel__body-title:hover{
background:#f0f0f0;
border:none;
}
.components-panel__body-toggle.components-button{
border:none;
box-shadow:none;
color:#1e1e1e;
font-weight:500;
height:auto;
outline:none;
padding:16px 16px 16px 48px;
position:relative;
text-align:right;
width:100%;
}
@media not (prefers-reduced-motion){
.components-panel__body-toggle.components-button{
transition:background .1s ease-in-out;
}
}
.components-panel__body-toggle.components-button:focus{
border-radius:0;
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-panel__body-toggle.components-button .components-panel__arrow{
color:#1e1e1e;
left:16px;
position:absolute;
top:50%;
transform:translateY(-50%);
fill:currentColor;
}
@media not (prefers-reduced-motion){
.components-panel__body-toggle.components-button .components-panel__arrow{
transition:color .1s ease-in-out;
}
}
body.rtl .components-panel__body-toggle.components-button .dashicons-arrow-right{
-ms-filter:fliph;
filter:FlipH;
margin-top:-10px;
transform:scaleX(-1);
}
.components-panel__icon{
color:#757575;
margin:-2px 6px -2px 0;
}
.components-panel__body-toggle-icon{
margin-left:-5px;
}
.components-panel__color-title{
float:right;
height:19px;
}
.components-panel__row{
align-items:center;
display:flex;
justify-content:space-between;
margin-top:8px;
min-height:36px;
}
.components-panel__row select{
min-width:0;
}
.components-panel__row label{
flex-shrink:0;
margin-left:12px;
max-width:75%;
}
.components-panel__row:empty,.components-panel__row:first-of-type{
margin-top:0;
}
.components-panel .circle-picker{
padding-bottom:20px;
}
.components-placeholder.components-placeholder{
align-items:flex-start;
box-sizing:border-box;
color:#1e1e1e;
display:flex;
flex-direction:column;
font-size:13px;
gap:16px;
margin:0;
padding:24px;
position:relative;
text-align:right;
width:100%;
-moz-font-smoothing:subpixel-antialiased;
-webkit-font-smoothing:subpixel-antialiased;
background-color:#fff;
border-radius:2px;
box-shadow:inset 0 0 0 1px #1e1e1e;
outline:1px solid #0000;
}
.components-placeholder__error,.components-placeholder__fieldset,.components-placeholder__instructions,.components-placeholder__label{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
font-weight:400;
letter-spacing:normal;
line-height:normal;
text-transform:none;
}
.components-placeholder__label{
align-items:center;
display:flex;
font-weight:600;
}
.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{
margin-left:4px;
fill:currentColor;
}
@media (forced-colors:active){
.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{
fill:CanvasText;
}
}
.components-placeholder__label:empty{
display:none;
}
.components-placeholder__fieldset,.components-placeholder__fieldset form{
display:flex;
flex-direction:row;
flex-wrap:wrap;
gap:16px;
justify-content:flex-start;
width:100%;
}
.components-placeholder__fieldset form p,.components-placeholder__fieldset p{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
}
.components-placeholder__fieldset.is-column-layout,.components-placeholder__fieldset.is-column-layout form{
flex-direction:column;
}
.components-placeholder__input[type=url]{
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
flex:1 1 auto;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
line-height:normal;
padding:6px 8px;
}
@media not (prefers-reduced-motion){
.components-placeholder__input[type=url]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-placeholder__input[type=url]{
font-size:13px;
line-height:normal;
}
}
.components-placeholder__input[type=url]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-placeholder__input[type=url]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-placeholder__input[type=url]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-placeholder__input[type=url]:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-placeholder__error{
gap:8px;
width:100%;
}
.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link{
margin-left:10px;
margin-right:10px;
}
.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link:last-child{
margin-left:0;
}
.components-placeholder.is-medium .components-placeholder__instructions,.components-placeholder.is-small .components-placeholder__instructions{
display:none;
}
.components-placeholder.is-medium .components-placeholder__fieldset,.components-placeholder.is-medium .components-placeholder__fieldset form,.components-placeholder.is-small .components-placeholder__fieldset,.components-placeholder.is-small .components-placeholder__fieldset form{
flex-direction:column;
}
.components-placeholder.is-medium .components-button,.components-placeholder.is-medium .components-placeholder__fieldset>*,.components-placeholder.is-small .components-button,.components-placeholder.is-small .components-placeholder__fieldset>*{
justify-content:center;
width:100%;
}
.components-placeholder.is-small{
padding:16px;
}
.components-placeholder.has-illustration{
-webkit-backdrop-filter:blur(100px);
backdrop-filter:blur(100px);
backface-visibility:hidden;
background-color:initial;
border-radius:0;
box-shadow:none;
color:inherit;
display:flex;
overflow:hidden;
}
.is-dark-theme .components-placeholder.has-illustration{
background-color:#0000001a;
}
.components-placeholder.has-illustration .components-placeholder__fieldset{
margin-left:0;
margin-right:0;
}
.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{
opacity:0;
pointer-events:none;
}
@media not (prefers-reduced-motion){
.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{
transition:opacity .1s linear;
}
}
.is-selected>.components-placeholder.has-illustration .components-button,.is-selected>.components-placeholder.has-illustration .components-placeholder__instructions,.is-selected>.components-placeholder.has-illustration .components-placeholder__label{
opacity:1;
pointer-events:auto;
}
.components-placeholder.has-illustration:before{
background:currentColor;
bottom:0;
content:"";
left:0;
opacity:.1;
pointer-events:none;
position:absolute;
right:0;
top:0;
}
.is-selected .components-placeholder.has-illustration{
overflow:auto;
}
.components-placeholder__preview{
display:flex;
justify-content:center;
}
.components-placeholder__illustration{
box-sizing:initial;
height:100%;
position:absolute;
right:50%;
top:50%;
transform:translate(50%, -50%);
width:100%;
stroke:currentColor;
opacity:.25;
}
.components-popover{
box-sizing:border-box;
will-change:transform;
z-index:1000000;
}
.components-popover *,.components-popover :after,.components-popover :before{
box-sizing:inherit;
}
.components-popover.is-expanded{
bottom:0;
left:0;
position:fixed;
right:0;
top:0;
z-index:1000000 !important;
}
.components-popover__content{
background:#fff;
border-radius:4px;
box-shadow:0 0 0 1px #ccc,0 2px 3px #0000000d,0 4px 5px #0000000a,0 12px 12px #00000008,0 16px 16px #00000005;
box-sizing:border-box;
width:min-content;
}
.is-alternate .components-popover__content{
border-radius:2px;
box-shadow:0 0 0 1px #1e1e1e;
}
.is-unstyled .components-popover__content{
background:none;
border-radius:0;
box-shadow:none;
}
.components-popover.is-expanded .components-popover__content{
box-shadow:0 -1px 0 0 #ccc;
height:calc(100% - 48px);
overflow-y:visible;
position:static;
width:auto;
}
.components-popover.is-expanded.is-alternate .components-popover__content{
box-shadow:0 -1px 0 #1e1e1e;
}
.components-popover__header{
align-items:center;
background:#fff;
display:flex;
height:48px;
justify-content:space-between;
padding:0 16px 0 8px;
}
.components-popover__header-title{
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
width:100%;
}
.components-popover__close.components-button{
z-index:5;
}
.components-popover__arrow{
display:flex;
height:14px;
pointer-events:none;
position:absolute;
width:14px;
}
.components-popover__arrow:before{
background-color:#fff;
content:"";
height:2px;
left:1px;
position:absolute;
right:1px;
top:-1px;
}
.components-popover__arrow.is-top{
bottom:-14px !important;
transform:rotate(0);
}
.components-popover__arrow.is-right{
left:-14px !important;
transform:rotate(90deg);
}
.components-popover__arrow.is-bottom{
top:-14px !important;
transform:rotate(180deg);
}
.components-popover__arrow.is-left{
right:-14px !important;
transform:rotate(-90deg);
}
.components-popover__triangle{
display:block;
flex:1;
}
.components-popover__triangle-bg{
fill:#fff;
}
.components-popover__triangle-border{
fill:#0000;
stroke-width:1px;
stroke:#ccc;
}
.is-alternate .components-popover__triangle-border{
stroke:#1e1e1e;
}
.components-radio-control{
border:0;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
margin:0;
padding:0;
}
.components-radio-control__group-wrapper.has-help{
margin-block-end:12px;
}
.components-radio-control__option{
align-items:center;
column-gap:8px;
display:grid;
grid-template-columns:auto 1fr;
grid-template-rows:auto minmax(0, max-content);
}
.components-radio-control__input[type=radio]{
appearance:none;
border:1px solid #1e1e1e;
border-radius:2px;
border-radius:50%;
box-shadow:0 0 0 #0000;
cursor:pointer;
display:inline-flex;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
grid-column:1;
grid-row:1;
height:24px;
line-height:normal;
margin:0;
max-width:24px;
min-width:24px;
padding:0;
position:relative;
transition:none;
width:24px;
}
@media not (prefers-reduced-motion){
.components-radio-control__input[type=radio]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-radio-control__input[type=radio]{
font-size:13px;
line-height:normal;
}
}
.components-radio-control__input[type=radio]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
}
.components-radio-control__input[type=radio]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-radio-control__input[type=radio]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-radio-control__input[type=radio]:-ms-input-placeholder{
color:#1e1e1e9e;
}
@media (min-width:600px){
.components-radio-control__input[type=radio]{
height:16px;
max-width:16px;
min-width:16px;
width:16px;
}
}
.components-radio-control__input[type=radio]:checked:before{
background-color:#fff;
border:4px solid #fff;
box-sizing:inherit;
height:12px;
margin:0;
position:absolute;
right:50%;
top:50%;
transform:translate(50%, -50%);
width:12px;
}
@media (min-width:600px){
.components-radio-control__input[type=radio]:checked:before{
height:8px;
width:8px;
}
}
.components-radio-control__input[type=radio]:focus{
box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--wp-admin-theme-color);
}
.components-radio-control__input[type=radio]:checked{
background:var(--wp-admin-theme-color);
border:none;
}
.components-radio-control__input[type=radio]:focus{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);
outline:2px solid #0000;
outline-offset:2px;
}
.components-radio-control__input[type=radio]:checked{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-radio-control__input[type=radio]:checked:before{
border-radius:50%;
content:"";
}
.components-radio-control__label{
cursor:pointer;
grid-column:2;
grid-row:1;
line-height:24px;
}
@media (min-width:600px){
.components-radio-control__label{
line-height:16px;
}
}
.components-radio-control__option-description{
grid-column:2;
grid-row:2;
padding-block-start:4px;
}
.components-radio-control__option-description.components-radio-control__option-description{
margin-top:0;
}
.components-resizable-box__handle{
display:none;
height:23px;
width:23px;
z-index:2;
}
.components-resizable-box__container.has-show-handle .components-resizable-box__handle{
display:block;
}
.components-resizable-box__handle>div{
height:100%;
outline:none;
position:relative;
width:100%;
z-index:2;
}
.components-resizable-box__container>img{
width:inherit;
}
.components-resizable-box__handle:after{
background:#fff;
border-radius:50%;
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)), 0 1px 1px #00000008, 0 1px 2px #00000005, 0 3px 3px #00000005, 0 4px 4px #00000003;
content:"";
cursor:inherit;
display:block;
height:15px;
left:calc(50% - 8px);
outline:2px solid #0000;
position:absolute;
top:calc(50% - 8px);
width:15px;
}
.components-resizable-box__side-handle:before{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-radius:9999px;
content:"";
cursor:inherit;
display:block;
height:3px;
left:calc(50% - 1px);
opacity:0;
position:absolute;
top:calc(50% - 1px);
width:3px;
}
@media not (prefers-reduced-motion){
.components-resizable-box__side-handle:before{
transition:transform .1s ease-in;
will-change:transform;
}
}
.components-resizable-box__corner-handle,.components-resizable-box__side-handle{
z-index:2;
}
.components-resizable-box__side-handle.components-resizable-box__handle-bottom,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:before,.components-resizable-box__side-handle.components-resizable-box__handle-top,.components-resizable-box__side-handle.components-resizable-box__handle-top:before{
border-left:0;
border-right:0;
right:0;
width:100%;
}
.components-resizable-box__side-handle.components-resizable-box__handle-left,.components-resizable-box__side-handle.components-resizable-box__handle-left:before,.components-resizable-box__side-handle.components-resizable-box__handle-right,.components-resizable-box__side-handle.components-resizable-box__handle-right:before{
border-bottom:0;
border-top:0;
height:100%;
top:0;
}
@media not (prefers-reduced-motion){
.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{
animation:components-resizable-box__top-bottom-animation .1s ease-out 0s;
animation-fill-mode:forwards;
}
.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before{
animation:components-resizable-box__left-right-animation .1s ease-out 0s;
animation-fill-mode:forwards;
}
}
@media not all and (min-resolution:0.001dpcm){
@supports (-webkit-appearance:none){
.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{
animation:none;
}
}
}
@keyframes components-resizable-box__top-bottom-animation{
0%{
opacity:0;
transform:scaleX(0);
}
to{
opacity:1;
transform:scaleX(1);
}
}
@keyframes components-resizable-box__left-right-animation{
0%{
opacity:0;
transform:scaleY(0);
}
to{
opacity:1;
transform:scaleY(1);
}
}
.components-resizable-box__handle-right{
right:-11.5px;
}
.components-resizable-box__handle-left{
left:-11.5px;
}
.components-resizable-box__handle-top{
top:-11.5px;
}
.components-resizable-box__handle-bottom{
bottom:-11.5px;
}
.components-responsive-wrapper{
align-items:center;
display:flex;
justify-content:center;
max-width:100%;
position:relative;
}
.components-responsive-wrapper__content{
display:block;
max-width:100%;
width:100%;
}
.components-sandbox{
overflow:hidden;
}
iframe.components-sandbox{
width:100%;
}
body.lockscroll,html.lockscroll{
overflow:hidden;
}
.components-select-control__input{
outline:0;
-webkit-tap-highlight-color:rgba(0, 0, 0, 0) !important;
}
@media (max-width:782px){
.components-base-control .components-base-control__field .components-select-control__input{
font-size:16px;
}
}
.components-snackbar{
-webkit-backdrop-filter:blur(16px) saturate(180%);
backdrop-filter:blur(16px) saturate(180%);
background:#000000d9;
border-radius:4px;
box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;
box-sizing:border-box;
color:#fff;
cursor:pointer;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
max-width:600px;
padding:12px 20px;
pointer-events:auto;
width:100%;
}
@media (min-width:600px){
.components-snackbar{
width:fit-content;
}
}
.components-snackbar:focus{
box-shadow:inset 0 0 0 1px #fff, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-snackbar.components-snackbar-explicit-dismiss{
cursor:default;
}
.components-snackbar .components-snackbar__content-with-icon{
padding-right:24px;
position:relative;
}
.components-snackbar .components-snackbar__icon{
position:absolute;
right:-8px;
top:-2.9px;
}
.components-snackbar .components-snackbar__dismiss-button{
cursor:pointer;
margin-right:24px;
}
.components-snackbar__action.components-button{
color:#fff;
flex-shrink:0;
margin-right:32px;
}
.components-snackbar__action.components-button:focus{
box-shadow:none;
outline:1px dotted #fff;
}
.components-snackbar__action.components-button:hover{
color:currentColor;
text-decoration:none;
}
.components-snackbar__content{
align-items:baseline;
display:flex;
justify-content:space-between;
line-height:1.4;
}
.components-snackbar-list{
box-sizing:border-box;
pointer-events:none;
position:absolute;
width:100%;
z-index:100000;
}
.components-snackbar-list__notice-container{
padding-top:8px;
position:relative;
}
.components-tab-panel__tabs{
align-items:stretch;
display:flex;
flex-direction:row;
}
.components-tab-panel__tabs[aria-orientation=vertical]{
flex-direction:column;
}
.components-tab-panel__tabs-item{
background:#0000;
border:none;
border-radius:0;
box-shadow:none;
cursor:pointer;
font-weight:500;
height:48px !important;
margin-right:0;
padding:3px 16px;
position:relative;
}
.components-tab-panel__tabs-item:focus:not(:disabled){
box-shadow:none;
outline:none;
position:relative;
}
.components-tab-panel__tabs-item:after{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-radius:0;
bottom:0;
content:"";
height:calc(var(--wp-admin-border-width-focus)*0);
left:0;
pointer-events:none;
position:absolute;
right:0;
}
@media not (prefers-reduced-motion){
.components-tab-panel__tabs-item:after{
transition:all .1s linear;
}
}
.components-tab-panel__tabs-item.is-active:after{
height:calc(var(--wp-admin-border-width-focus)*1);
outline:2px solid #0000;
outline-offset:-1px;
}
.components-tab-panel__tabs-item:before{
border-radius:2px;
bottom:12px;
box-shadow:0 0 0 0 #0000;
content:"";
left:12px;
pointer-events:none;
position:absolute;
right:12px;
top:12px;
}
@media not (prefers-reduced-motion){
.components-tab-panel__tabs-item:before{
transition:all .1s linear;
}
}
.components-tab-panel__tabs-item:focus-visible:before{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
}
.components-tab-panel__tab-content:focus{
box-shadow:none;
outline:none;
}
.components-tab-panel__tab-content:focus-visible{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
outline-offset:0;
}
.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
height:32px;
line-height:normal;
margin:0;
padding:6px 8px;
width:100%;
}
@media not (prefers-reduced-motion){
.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{
font-size:13px;
line-height:normal;
}
}
.components-text-control__input:focus,.components-text-control__input[type=color]:focus,.components-text-control__input[type=date]:focus,.components-text-control__input[type=datetime-local]:focus,.components-text-control__input[type=datetime]:focus,.components-text-control__input[type=email]:focus,.components-text-control__input[type=month]:focus,.components-text-control__input[type=number]:focus,.components-text-control__input[type=password]:focus,.components-text-control__input[type=tel]:focus,.components-text-control__input[type=text]:focus,.components-text-control__input[type=time]:focus,.components-text-control__input[type=url]:focus,.components-text-control__input[type=week]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-text-control__input::-webkit-input-placeholder,.components-text-control__input[type=color]::-webkit-input-placeholder,.components-text-control__input[type=date]::-webkit-input-placeholder,.components-text-control__input[type=datetime-local]::-webkit-input-placeholder,.components-text-control__input[type=datetime]::-webkit-input-placeholder,.components-text-control__input[type=email]::-webkit-input-placeholder,.components-text-control__input[type=month]::-webkit-input-placeholder,.components-text-control__input[type=number]::-webkit-input-placeholder,.components-text-control__input[type=password]::-webkit-input-placeholder,.components-text-control__input[type=tel]::-webkit-input-placeholder,.components-text-control__input[type=text]::-webkit-input-placeholder,.components-text-control__input[type=time]::-webkit-input-placeholder,.components-text-control__input[type=url]::-webkit-input-placeholder,.components-text-control__input[type=week]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-text-control__input::-moz-placeholder,.components-text-control__input[type=color]::-moz-placeholder,.components-text-control__input[type=date]::-moz-placeholder,.components-text-control__input[type=datetime-local]::-moz-placeholder,.components-text-control__input[type=datetime]::-moz-placeholder,.components-text-control__input[type=email]::-moz-placeholder,.components-text-control__input[type=month]::-moz-placeholder,.components-text-control__input[type=number]::-moz-placeholder,.components-text-control__input[type=password]::-moz-placeholder,.components-text-control__input[type=tel]::-moz-placeholder,.components-text-control__input[type=text]::-moz-placeholder,.components-text-control__input[type=time]::-moz-placeholder,.components-text-control__input[type=url]::-moz-placeholder,.components-text-control__input[type=week]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-text-control__input:-ms-input-placeholder,.components-text-control__input[type=color]:-ms-input-placeholder,.components-text-control__input[type=date]:-ms-input-placeholder,.components-text-control__input[type=datetime-local]:-ms-input-placeholder,.components-text-control__input[type=datetime]:-ms-input-placeholder,.components-text-control__input[type=email]:-ms-input-placeholder,.components-text-control__input[type=month]:-ms-input-placeholder,.components-text-control__input[type=number]:-ms-input-placeholder,.components-text-control__input[type=password]:-ms-input-placeholder,.components-text-control__input[type=tel]:-ms-input-placeholder,.components-text-control__input[type=text]:-ms-input-placeholder,.components-text-control__input[type=time]:-ms-input-placeholder,.components-text-control__input[type=url]:-ms-input-placeholder,.components-text-control__input[type=week]:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-text-control__input.is-next-40px-default-size,.components-text-control__input[type=color].is-next-40px-default-size,.components-text-control__input[type=date].is-next-40px-default-size,.components-text-control__input[type=datetime-local].is-next-40px-default-size,.components-text-control__input[type=datetime].is-next-40px-default-size,.components-text-control__input[type=email].is-next-40px-default-size,.components-text-control__input[type=month].is-next-40px-default-size,.components-text-control__input[type=number].is-next-40px-default-size,.components-text-control__input[type=password].is-next-40px-default-size,.components-text-control__input[type=tel].is-next-40px-default-size,.components-text-control__input[type=text].is-next-40px-default-size,.components-text-control__input[type=time].is-next-40px-default-size,.components-text-control__input[type=url].is-next-40px-default-size,.components-text-control__input[type=week].is-next-40px-default-size{
height:40px;
padding-left:12px;
padding-right:12px;
}
.components-text-control__input[type=email],.components-text-control__input[type=url]{
direction:ltr;
}
.components-tip{
color:#757575;
display:flex;
}
.components-tip svg{
align-self:center;
fill:#f0b849;
flex-shrink:0;
margin-left:16px;
}
.components-tip p{
margin:0;
}
.components-toggle-control__label{
line-height:16px;
}
.components-toggle-control__label:not(.is-disabled){
cursor:pointer;
}
.components-toggle-control__help{
display:inline-block;
margin-inline-start:40px;
}
.components-accessible-toolbar{
border:1px solid #1e1e1e;
border-radius:2px;
display:inline-flex;
flex-shrink:0;
}
.components-accessible-toolbar>.components-toolbar-group:last-child{
border-left:none;
}
.components-accessible-toolbar.is-unstyled{
border:none;
}
.components-accessible-toolbar.is-unstyled>.components-toolbar-group{
border-left:none;
}
.components-accessible-toolbar[aria-orientation=vertical],.components-toolbar[aria-orientation=vertical]{
align-items:center;
display:flex;
flex-direction:column;
}
.components-accessible-toolbar .components-button,.components-toolbar .components-button{
height:48px;
padding-left:16px;
padding-right:16px;
position:relative;
z-index:1;
}
.components-accessible-toolbar .components-button:focus:not(:disabled),.components-toolbar .components-button:focus:not(:disabled){
box-shadow:none;
outline:none;
}
.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{
border-radius:2px;
content:"";
display:block;
height:32px;
left:8px;
position:absolute;
right:8px;
z-index:-1;
}
@media not (prefers-reduced-motion){
.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{
animation:components-button__appear-animation .1s ease;
animation-fill-mode:forwards;
}
}
.components-accessible-toolbar .components-button svg,.components-toolbar .components-button svg{
margin-left:auto;
margin-right:auto;
position:relative;
}
.components-accessible-toolbar .components-button.is-pressed,.components-accessible-toolbar .components-button.is-pressed:hover,.components-toolbar .components-button.is-pressed,.components-toolbar .components-button.is-pressed:hover{
background:#0000;
}
.components-accessible-toolbar .components-button.is-pressed:before,.components-toolbar .components-button.is-pressed:before{
background:#1e1e1e;
}
.components-accessible-toolbar .components-button:focus:before,.components-toolbar .components-button:focus:before{
box-shadow:inset 0 0 0 1px #fff, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-accessible-toolbar .components-button.has-icon.has-icon,.components-toolbar .components-button.has-icon.has-icon{
min-width:48px;
padding-left:8px;
padding-right:8px;
}
@keyframes components-button__appear-animation{
0%{
transform:scaleY(0);
}
to{
transform:scaleY(1);
}
}
.components-toolbar__control.components-button{
position:relative;
}
.components-toolbar__control.components-button[data-subscript] svg{
padding:5px 0 5px 10px;
}
.components-toolbar__control.components-button[data-subscript]:after{
bottom:10px;
content:attr(data-subscript);
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
font-weight:600;
left:8px;
line-height:12px;
position:absolute;
}
.components-toolbar__control.components-button:not(:disabled).is-pressed[data-subscript]:after{
color:#fff;
}
.components-toolbar-group{
background-color:#fff;
border-left:1px solid #1e1e1e;
display:inline-flex;
flex-shrink:0;
flex-wrap:wrap;
line-height:0;
min-height:48px;
padding-left:6px;
padding-right:6px;
}
.components-toolbar-group .components-toolbar-group.components-toolbar-group{
border-width:0;
margin:0;
}
.components-toolbar-group .components-button.components-button,.components-toolbar-group .components-button.has-icon.has-icon{
justify-content:center;
min-width:36px;
padding-left:6px;
padding-right:6px;
}
.components-toolbar-group .components-button.components-button svg,.components-toolbar-group .components-button.has-icon.has-icon svg{
min-width:24px;
}
.components-toolbar-group .components-button.components-button:before,.components-toolbar-group .components-button.has-icon.has-icon:before{
left:2px;
right:2px;
}
.components-toolbar{
background-color:#fff;
border:1px solid #1e1e1e;
display:inline-flex;
flex-shrink:0;
flex-wrap:wrap;
margin:0;
min-height:48px;
}
.components-toolbar .components-toolbar.components-toolbar{
border-width:0;
margin:0;
}
div.components-toolbar>div{
display:flex;
margin:0;
}
div.components-toolbar>div+div.has-left-divider{
margin-right:6px;
overflow:visible;
position:relative;
}
div.components-toolbar>div+div.has-left-divider:before{
background-color:#ddd;
box-sizing:initial;
content:"";
display:inline-block;
height:20px;
position:absolute;
right:-3px;
top:8px;
width:1px;
}
.components-tooltip{
background:#000;
border-radius:2px;
box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;
color:#f0f0f0;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:12px;
line-height:1.4;
padding:4px 8px;
text-align:center;
z-index:1000002;
}
.components-tooltip__shortcut{
margin-right:8px;
}@charset "UTF-8";
:root{
--wp-admin-theme-color:#3858e9;
--wp-admin-theme-color--rgb:56, 88, 233;
--wp-admin-theme-color-darker-10:#2145e6;
--wp-admin-theme-color-darker-10--rgb:33, 69, 230;
--wp-admin-theme-color-darker-20:#183ad6;
--wp-admin-theme-color-darker-20--rgb:24, 58, 214;
--wp-admin-border-width-focus:2px;
}
@media (min-resolution:192dpi){
:root{
--wp-admin-border-width-focus:1.5px;
}
}
@media not (prefers-reduced-motion){
.components-animate__appear{
animation:components-animate__appear-animation .1s cubic-bezier(0, 0, .2, 1) 0s;
animation-fill-mode:forwards;
}
}
.components-animate__appear.is-from-top,.components-animate__appear.is-from-top.is-from-left{
transform-origin:top left;
}
.components-animate__appear.is-from-top.is-from-right{
transform-origin:top right;
}
.components-animate__appear.is-from-bottom,.components-animate__appear.is-from-bottom.is-from-left{
transform-origin:bottom left;
}
.components-animate__appear.is-from-bottom.is-from-right{
transform-origin:bottom right;
}
@keyframes components-animate__appear-animation{
0%{
transform:translateY(-2em) scaleY(0) scaleX(0);
}
to{
transform:translateY(0) scaleY(1) scaleX(1);
}
}
@media not (prefers-reduced-motion){
.components-animate__slide-in{
animation:components-animate__slide-in-animation .1s cubic-bezier(0, 0, .2, 1);
animation-fill-mode:forwards;
}
.components-animate__slide-in.is-from-left{
transform:translateX(100%);
}
.components-animate__slide-in.is-from-right{
transform:translateX(-100%);
}
}
@keyframes components-animate__slide-in-animation{
to{
transform:translateX(0);
}
}
@media not (prefers-reduced-motion){
.components-animate__loading{
animation:components-animate__loading 1.6s ease-in-out infinite;
}
}
@keyframes components-animate__loading{
0%{
opacity:.5;
}
50%{
opacity:1;
}
to{
opacity:.5;
}
}
.components-autocomplete__popover .components-popover__content{
min-width:200px;
padding:8px;
}
.components-autocomplete__result.components-button{
display:flex;
height:auto;
min-height:36px;
text-align:left;
width:100%;
}
.components-autocomplete__result.components-button:focus:not(:disabled){
box-shadow:inset 0 0 0 1px #fff, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-badge{
align-items:center;
background-color:color-mix(in srgb, #fff 90%, var(--base-color));
border-radius:2px;
box-sizing:border-box;
color:color-mix(in srgb, #000 50%, var(--base-color));
display:inline-flex;
font-size:12px;
font-weight:400;
gap:2px;
line-height:20px;
max-width:100%;
min-height:24px;
padding:0 8px;
}
.components-badge *,.components-badge :after,.components-badge :before{
box-sizing:inherit;
}
.components-badge:where(.is-default){
background-color:#f0f0f0;
color:#2f2f2f;
}
.components-badge.has-icon{
padding-inline-start:4px;
}
.components-badge.is-info{
--base-color:#3858e9;
}
.components-badge.is-warning{
--base-color:#f0b849;
}
.components-badge.is-error{
--base-color:#cc1818;
}
.components-badge.is-success{
--base-color:#4ab866;
}
.components-badge__icon{
flex-shrink:0;
}
.components-badge__content{
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.components-button-group{
display:inline-block;
}
.components-button-group .components-button{
border-radius:0;
box-shadow:inset 0 0 0 1px #1e1e1e;
color:#1e1e1e;
display:inline-flex;
}
.components-button-group .components-button+.components-button{
margin-left:-1px;
}
.components-button-group .components-button:first-child{
border-radius:2px 0 0 2px;
}
.components-button-group .components-button:last-child{
border-radius:0 2px 2px 0;
}
.components-button-group .components-button.is-primary,.components-button-group .components-button:focus{
position:relative;
z-index:1;
}
.components-button-group .components-button.is-primary{
box-shadow:inset 0 0 0 1px #1e1e1e;
}
.components-button{
align-items:center;
-webkit-appearance:none;
background:none;
border:0;
border-radius:2px;
box-sizing:border-box;
color:var(--wp-components-color-foreground, #1e1e1e);
cursor:pointer;
display:inline-flex;
font-family:inherit;
font-size:13px;
height:36px;
margin:0;
padding:6px 12px;
text-decoration:none;
}
@media not (prefers-reduced-motion){
.components-button{
transition:box-shadow .1s linear;
}
}
.components-button.is-next-40px-default-size{
height:40px;
}
.components-button:hover:not(:disabled,[aria-disabled=true]),.components-button[aria-expanded=true]{
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button:focus:not(:disabled){
box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:3px solid #0000;
}
.components-button.is-primary{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:var(--wp-components-color-accent-inverted, #fff);
outline:1px solid #0000;
text-decoration:none;
text-shadow:none;
white-space:nowrap;
}
.components-button.is-primary:hover:not(:disabled){
background:var(--wp-components-color-accent-darker-10, var(--wp-admin-theme-color-darker-10, #2145e6));
color:var(--wp-components-color-accent-inverted, #fff);
}
.components-button.is-primary:active:not(:disabled){
background:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
border-color:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
color:var(--wp-components-color-accent-inverted, #fff);
}
.components-button.is-primary:focus:not(:disabled){
box-shadow:inset 0 0 0 1px var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button.is-primary:disabled,.components-button.is-primary:disabled:active:enabled,.components-button.is-primary[aria-disabled=true],.components-button.is-primary[aria-disabled=true]:active:enabled,.components-button.is-primary[aria-disabled=true]:enabled{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:#fff6;
outline:none;
}
.components-button.is-primary:disabled:active:enabled:focus:enabled,.components-button.is-primary:disabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:active:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:focus:enabled{
box-shadow:inset 0 0 0 1px var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button.is-primary.is-busy,.components-button.is-primary.is-busy:disabled,.components-button.is-primary.is-busy[aria-disabled=true]{
background-image:linear-gradient(-45deg, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 33%, var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6)) 33%, var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6)) 70%, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 70%);
background-size:100px 100%;
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:var(--wp-components-color-accent-inverted, #fff);
}
.components-button.is-secondary,.components-button.is-tertiary{
outline:1px solid #0000;
}
.components-button.is-secondary:active:not(:disabled),.components-button.is-tertiary:active:not(:disabled){
box-shadow:none;
}
.components-button.is-secondary:disabled,.components-button.is-secondary[aria-disabled=true],.components-button.is-secondary[aria-disabled=true]:hover,.components-button.is-tertiary:disabled,.components-button.is-tertiary[aria-disabled=true],.components-button.is-tertiary[aria-disabled=true]:hover{
background:#0000;
color:#949494;
transform:none;
}
.components-button.is-secondary{
background:#0000;
box-shadow:inset 0 0 0 1px var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)), 0 0 0 currentColor;
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:1px solid #0000;
white-space:nowrap;
}
.components-button.is-secondary:hover:not(:disabled,[aria-disabled=true],.is-pressed){
background:color-mix(in srgb, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 4%, #0000);
box-shadow:inset 0 0 0 1px var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
color:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
}
.components-button.is-secondary:disabled:not(:focus),.components-button.is-secondary[aria-disabled=true]:hover:not(:focus),.components-button.is-secondary[aria-disabled=true]:not(:focus){
box-shadow:inset 0 0 0 1px #ddd;
}
.components-button.is-secondary:focus:not(:disabled){
box-shadow:0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-button.is-tertiary{
background:#0000;
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
white-space:nowrap;
}
.components-button.is-tertiary:hover:not(:disabled,[aria-disabled=true],.is-pressed){
background:color-mix(in srgb, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 4%, #0000);
color:var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
}
.components-button.is-tertiary:active:not(:disabled,[aria-disabled=true]){
background:color-mix(in srgb, var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)) 8%, #0000);
}
p+.components-button.is-tertiary{
margin-left:-6px;
}
.components-button.is-tertiary:disabled:not(:focus),.components-button.is-tertiary[aria-disabled=true]:hover:not(:focus),.components-button.is-tertiary[aria-disabled=true]:not(:focus){
box-shadow:none;
outline:none;
}
.components-button.is-destructive{
--wp-components-color-accent:#cc1818;
--wp-components-color-accent-darker-10:#9e1313;
--wp-components-color-accent-darker-20:#710d0d;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link){
color:#cc1818;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):hover:not(:disabled,[aria-disabled=true]){
color:#710d0d;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):focus{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #cc1818;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):active:not(:disabled,[aria-disabled=true]){
background:#ccc;
}
.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):disabled,.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link)[aria-disabled=true]{
color:#949494;
}
.components-button.is-destructive.is-secondary:hover:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:hover:not(:disabled,[aria-disabled=true]){
background:#cc18180a;
}
.components-button.is-destructive.is-secondary:active:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:active:not(:disabled,[aria-disabled=true]){
background:#cc181814;
}
.components-button.is-link{
background:none;
border:0;
border-radius:0;
box-shadow:none;
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
height:auto;
margin:0;
outline:none;
padding:0;
text-align:left;
text-decoration:underline;
}
@media not (prefers-reduced-motion){
.components-button.is-link{
transition-duration:.05s;
transition-property:border, background, color;
transition-timing-function:ease-in-out;
}
}
.components-button.is-link:focus{
border-radius:2px;
}
.components-button.is-link:disabled,.components-button.is-link[aria-disabled=true]{
color:#949494;
}
.components-button:not(:disabled,[aria-disabled=true]):active{
color:var(--wp-components-color-foreground, #1e1e1e);
}
.components-button:disabled,.components-button[aria-disabled=true]{
color:#949494;
cursor:default;
}
.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{
background-image:linear-gradient(-45deg, #fafafa 33%, #e0e0e0 0, #e0e0e0 70%, #fafafa 0);
background-size:100px 100%;
}
@media not (prefers-reduced-motion){
.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{
animation:components-button__busy-animation 2.5s linear infinite;
}
}
.components-button.is-compact{
height:32px;
}
.components-button.is-compact.has-icon:not(.has-text){
min-width:32px;
padding:0;
width:32px;
}
.components-button.is-small{
font-size:11px;
height:24px;
line-height:22px;
padding:0 8px;
}
.components-button.is-small.has-icon:not(.has-text){
min-width:24px;
padding:0;
width:24px;
}
.components-button.has-icon{
justify-content:center;
min-width:36px;
padding:6px;
}
.components-button.has-icon.is-next-40px-default-size{
min-width:40px;
}
.components-button.has-icon .dashicon{
align-items:center;
box-sizing:initial;
display:inline-flex;
justify-content:center;
padding:2px;
}
.components-button.has-icon.has-text{
gap:4px;
justify-content:start;
padding-left:8px;
padding-right:12px;
}
.components-button.is-pressed,.components-button.is-pressed:hover{
color:var(--wp-components-color-foreground-inverted, #fff);
}
.components-button.is-pressed:hover:not(:disabled,[aria-disabled=true]),.components-button.is-pressed:not(:disabled,[aria-disabled=true]){
background:var(--wp-components-color-foreground, #1e1e1e);
}
.components-button.is-pressed:disabled,.components-button.is-pressed[aria-disabled=true]{
color:#949494;
}
.components-button.is-pressed:disabled:not(.is-primary):not(.is-secondary):not(.is-tertiary),.components-button.is-pressed[aria-disabled=true]:not(.is-primary):not(.is-secondary):not(.is-tertiary){
background:#949494;
color:var(--wp-components-color-foreground-inverted, #fff);
}
.components-button.is-pressed:focus:not(:disabled){
box-shadow:inset 0 0 0 1px var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
}
.components-button svg{
fill:currentColor;
outline:none;
}
@media (forced-colors:active){
.components-button svg{
fill:CanvasText;
}
}
.components-button .components-visually-hidden{
height:auto;
}
@keyframes components-button__busy-animation{
0%{
background-position:200px 0;
}
}
.components-checkbox-control{
--checkbox-input-size:24px;
--checkbox-input-margin:8px;
}
@media (min-width:600px){
.components-checkbox-control{
--checkbox-input-size:16px;
}
}
.components-checkbox-control__label{
cursor:pointer;
line-height:var(--checkbox-input-size);
}
.components-checkbox-control__input[type=checkbox]{
appearance:none;
background:#fff;
border:1px solid #1e1e1e;
border-radius:2px;
box-shadow:0 0 0 #0000;
clear:none;
color:#1e1e1e;
cursor:pointer;
display:inline-block;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
height:var(--checkbox-input-size);
line-height:normal;
line-height:0;
margin:0 4px 0 0;
outline:0;
padding:6px 8px;
padding:0 !important;
text-align:center;
transition:none;
vertical-align:top;
width:var(--checkbox-input-size);
}
@media not (prefers-reduced-motion){
.components-checkbox-control__input[type=checkbox]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-checkbox-control__input[type=checkbox]{
font-size:13px;
line-height:normal;
}
}
.components-checkbox-control__input[type=checkbox]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-checkbox-control__input[type=checkbox]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-checkbox-control__input[type=checkbox]:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-checkbox-control__input[type=checkbox]:focus{
box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox]:checked{
background:var(--wp-admin-theme-color);
border-color:var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox]:checked::-ms-check{
opacity:0;
}
.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
color:#fff;
margin:-3px -5px;
}
@media (min-width:782px){
.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
margin:-4px 0 0 -5px;
}
}
.components-checkbox-control__input[type=checkbox][aria-checked=mixed]{
background:var(--wp-admin-theme-color);
border-color:var(--wp-admin-theme-color);
}
.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
content:"\f460";
display:inline-block;
float:left;
font:normal 30px/1 dashicons;
vertical-align:middle;
width:16px;
speak:none;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
@media (min-width:782px){
.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{
float:none;
font-size:21px;
}
}
.components-checkbox-control__input[type=checkbox]:disabled,.components-checkbox-control__input[type=checkbox][aria-disabled=true]{
background:#f0f0f0;
border-color:#ddd;
cursor:default;
opacity:1;
}
@media not (prefers-reduced-motion){
.components-checkbox-control__input[type=checkbox]{
transition:border-color .1s ease-in-out;
}
}
.components-checkbox-control__input[type=checkbox]:focus{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);
outline:2px solid #0000;
outline-offset:2px;
}
.components-checkbox-control__input[type=checkbox]:checked,.components-checkbox-control__input[type=checkbox]:indeterminate{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-checkbox-control__input[type=checkbox]:checked::-ms-check,.components-checkbox-control__input[type=checkbox]:indeterminate::-ms-check{
opacity:0;
}
.components-checkbox-control__input[type=checkbox]:checked:before{
content:none;
}
.components-checkbox-control__input-container{
aspect-ratio:1;
display:inline-block;
flex-shrink:0;
line-height:1;
margin-right:var(--checkbox-input-margin);
position:relative;
vertical-align:middle;
width:var(--checkbox-input-size);
}
svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{
--checkmark-size:var(--checkbox-input-size);
fill:#fff;
cursor:pointer;
height:var(--checkmark-size);
left:50%;
pointer-events:none;
position:absolute;
top:50%;
transform:translate(-50%, -50%);
-webkit-user-select:none;
user-select:none;
width:var(--checkmark-size);
}
@media (min-width:600px){
svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{
--checkmark-size:calc(var(--checkbox-input-size) + 4px);
}
}
.components-checkbox-control__help{
display:inline-block;
margin-inline-start:calc(var(--checkbox-input-size) + var(--checkbox-input-margin));
}
.components-circular-option-picker{
display:inline-block;
min-width:188px;
width:100%;
}
.components-circular-option-picker .components-circular-option-picker__custom-clear-wrapper{
display:flex;
justify-content:flex-end;
margin-top:12px;
}
.components-circular-option-picker .components-circular-option-picker__swatches{
display:flex;
flex-wrap:wrap;
gap:12px;
position:relative;
z-index:1;
}
.components-circular-option-picker>:not(.components-circular-option-picker__swatches){
position:relative;
z-index:0;
}
.components-circular-option-picker__option-wrapper{
display:inline-block;
height:28px;
transform:scale(1);
vertical-align:top;
width:28px;
}
@media not (prefers-reduced-motion){
.components-circular-option-picker__option-wrapper{
transition:transform .1s ease;
will-change:transform;
}
}
.components-circular-option-picker__option-wrapper:hover{
transform:scale(1.2);
}
.components-circular-option-picker__option-wrapper>div{
height:100%;
width:100%;
}
.components-circular-option-picker__option-wrapper:before{
background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' fill='none'%3E%3Cpath fill='%23555D65' d='M6 8V6H4v2zm2 0V6h2v2zm2 8H8v-2h2zm2 0v-2h2v2zm0 2v-2h-2v2H8v2h2v-2zm2 0v2h-2v-2zm2 0h-2v-2h2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M18 18h2v-2h-2v-2h2v-2h-2v-2h2V8h-2v2h-2V8h-2v2h2v2h-2v2h2v2h2zm-2-4v-2h2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' d='M18 18v2h-2v-2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M8 10V8H6v2H4v2h2v2H4v2h2v2H4v2h2v2H4v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2v2h-2V4h-2v2h-2V4h-2v2h-2V4h-2v2h2v2h-2v2zm0 2v-2H6v2zm2 0v-2h2v2zm0 2v-2H8v2H6v2h2v2H6v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h-2v2h-2V6h-2v2h-2v2h2v2h-2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M4 0H2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2H8V0H6v2H4zm0 4V2H2v2zm2 0V2h2v2zm0 2V4H4v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2H8v2z' clip-rule='evenodd'/%3E%3C/svg%3E");
border-radius:50%;
bottom:1px;
content:"";
left:1px;
position:absolute;
right:1px;
top:1px;
z-index:-1;
}
.components-circular-option-picker__option{
aspect-ratio:1;
background:#0000;
border:none;
border-radius:50%;
box-shadow:inset 0 0 0 14px;
cursor:pointer;
display:inline-block;
height:100% !important;
vertical-align:top;
}
@media not (prefers-reduced-motion){
.components-circular-option-picker__option{
transition:box-shadow .1s ease;
}
}
.components-circular-option-picker__option:hover{
box-shadow:inset 0 0 0 14px !important;
}
.components-circular-option-picker__option[aria-pressed=true],.components-circular-option-picker__option[aria-selected=true]{
box-shadow:inset 0 0 0 4px;
overflow:visible;
position:relative;
z-index:1;
}
.components-circular-option-picker__option[aria-pressed=true]+svg,.components-circular-option-picker__option[aria-selected=true]+svg{
border-radius:50%;
left:2px;
pointer-events:none;
position:absolute;
top:2px;
z-index:2;
}
.components-circular-option-picker__option:after{
border:1px solid #0000;
border-radius:50%;
bottom:-1px;
box-shadow:inset 0 0 0 1px #0003;
box-sizing:inherit;
content:"";
left:-1px;
position:absolute;
right:-1px;
top:-1px;
}
.components-circular-option-picker__option:focus:after{
border:2px solid #757575;
border-radius:50%;
box-shadow:inset 0 0 0 2px #fff;
content:"";
height:calc(100% + 4px);
left:50%;
position:absolute;
top:50%;
transform:translate(-50%, -50%);
width:calc(100% + 4px);
}
.components-circular-option-picker__option.components-button:focus{
background-color:initial;
box-shadow:inset 0 0 0 14px;
outline:none;
}
.components-circular-option-picker__button-action .components-circular-option-picker__option{
background:#fff;
color:#fff;
}
.components-circular-option-picker__dropdown-link-action{
margin-right:16px;
}
.components-circular-option-picker__dropdown-link-action .components-button{
line-height:22px;
}
.components-palette-edit__popover-gradient-picker{
padding:8px;
width:260px;
}
.components-dropdown-menu__menu .components-palette-edit__menu-button{
width:100%;
}
.component-color-indicator{
background:#fff linear-gradient(-45deg, #0000 48%, #ddd 0, #ddd 52%, #0000 0);
border-radius:50%;
box-shadow:inset 0 0 0 1px #0003;
display:inline-block;
height:20px;
padding:0;
width:20px;
}
.components-combobox-control{
width:100%;
}
input.components-combobox-control__input[type=text]{
border:none;
box-shadow:none;
font-family:inherit;
font-size:16px;
line-height:inherit;
margin:0;
min-height:auto;
padding:2px;
width:100%;
}
@media (min-width:600px){
input.components-combobox-control__input[type=text]{
font-size:13px;
}
}
input.components-combobox-control__input[type=text]:focus{
box-shadow:none;
outline:none;
}
.components-combobox-control__suggestions-container{
align-items:flex-start;
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
display:flex;
flex-wrap:wrap;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
line-height:normal;
padding:0;
width:100%;
}
@media not (prefers-reduced-motion){
.components-combobox-control__suggestions-container{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-combobox-control__suggestions-container{
font-size:13px;
line-height:normal;
}
}
.components-combobox-control__suggestions-container:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-combobox-control__suggestions-container::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-combobox-control__suggestions-container::-moz-placeholder{
color:#1e1e1e9e;
}
.components-combobox-control__suggestions-container:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-combobox-control__suggestions-container:focus-within{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-combobox-control__suggestions-container .components-spinner{
margin:0;
}
.components-color-palette__custom-color-wrapper{
position:relative;
z-index:0;
}
.components-color-palette__custom-color-button{
background:none;
border:none;
border-radius:4px 4px 0 0;
box-shadow:inset 0 0 0 1px #0003;
box-sizing:border-box;
cursor:pointer;
height:64px;
outline:1px solid #0000;
position:relative;
width:100%;
}
.components-color-palette__custom-color-button:focus{
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline-width:2px;
}
.components-color-palette__custom-color-button:after{
background-image:repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0), repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0);
background-position:0 0, 24px 24px;
background-size:48px 48px;
border-radius:3px 3px 0 0;
content:"";
inset:1px;
position:absolute;
z-index:-1;
}
.components-color-palette__custom-color-text-wrapper{
border-radius:0 0 4px 4px;
box-shadow:inset 0 -1px 0 0 #0003,inset 1px 0 0 0 #0003,inset -1px 0 0 0 #0003;
font-size:13px;
padding:12px 16px;
position:relative;
}
.components-color-palette__custom-color-name{
color:var(--wp-components-color-foreground, #1e1e1e);
margin:0 1px;
}
.components-color-palette__custom-color-value{
color:#757575;
}
.components-color-palette__custom-color-value--is-hex{
text-transform:uppercase;
}
.components-color-palette__custom-color-value:empty:after{
content:"";
visibility:hidden;
}
.components-custom-gradient-picker__gradient-bar{
border-radius:2px;
height:48px;
position:relative;
width:100%;
z-index:1;
}
.components-custom-gradient-picker__gradient-bar.has-gradient{
background-image:repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0), repeating-linear-gradient(45deg, #e0e0e0 25%, #0000 0, #0000 75%, #e0e0e0 0, #e0e0e0);
background-position:0 0, 12px 12px;
background-size:24px 24px;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__gradient-bar-background{
inset:0;
position:absolute;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__markers-container{
margin-left:auto;
margin-right:auto;
position:relative;
width:calc(100% - 48px);
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-dropdown{
display:flex;
height:16px;
position:absolute;
top:16px;
width:16px;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown{
background:#fff;
border-radius:50%;
color:#1e1e1e;
height:inherit;
min-width:16px !important;
padding:2px;
position:relative;
width:inherit;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown svg{
height:100%;
width:100%;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button{
border-radius:50%;
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 2px 0 #00000040;
height:inherit;
outline:2px solid #0000;
padding:0;
width:inherit;
}
.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button.is-active,.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button:focus{
box-shadow:inset 0 0 0 calc(var(--wp-admin-border-width-focus)*2) #fff, 0 0 2px 0 #00000040;
outline:1.5px solid #0000;
}
.components-custom-gradient-picker__remove-control-point-wrapper{
padding-bottom:8px;
}
.components-custom-gradient-picker__inserter{
direction:ltr;
}
.components-custom-gradient-picker__liner-gradient-indicator{
display:inline-block;
flex:0 auto;
height:20px;
width:20px;
}
.components-custom-gradient-picker__ui-line{
position:relative;
z-index:0;
}
.block-editor-dimension-control .components-base-control__field{
align-items:center;
display:flex;
}
.block-editor-dimension-control .components-base-control__label{
align-items:center;
display:flex;
margin-bottom:0;
margin-right:1em;
}
.block-editor-dimension-control .components-base-control__label .dashicon{
margin-right:.5em;
}
.block-editor-dimension-control.is-manual .components-base-control__label{
width:10em;
}
body.is-dragging-components-draggable{
cursor:move;
cursor:grabbing !important;
}
.components-draggable__invisible-drag-image{
height:50px;
left:-1000px;
position:fixed;
width:50px;
}
.components-draggable__clone{
background:#0000;
padding:0;
pointer-events:none;
position:fixed;
z-index:1000000000;
}
.components-drop-zone{
border-radius:2px;
bottom:0;
left:0;
opacity:0;
position:absolute;
right:0;
top:0;
visibility:hidden;
z-index:40;
}
.components-drop-zone.is-active{
opacity:1;
visibility:visible;
}
.components-drop-zone .components-drop-zone__content{
align-items:center;
background-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
bottom:0;
color:#fff;
display:flex;
height:100%;
justify-content:center;
left:0;
opacity:0;
pointer-events:none;
position:absolute;
right:0;
text-align:center;
top:0;
width:100%;
z-index:50;
}
.components-drop-zone .components-drop-zone__content-inner{
opacity:0;
transform:scale(.9);
}
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{
opacity:1;
}
@media not (prefers-reduced-motion){
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{
transition:opacity .2s ease-in-out;
}
}
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{
opacity:1;
transform:scale(1);
}
@media not (prefers-reduced-motion){
.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{
transition:opacity .1s ease-in-out .1s,transform .1s ease-in-out .1s;
}
}
.components-drop-zone__content-icon,.components-drop-zone__content-text{
display:block;
}
.components-drop-zone__content-icon{
line-height:0;
margin:0 auto 8px;
fill:currentColor;
pointer-events:none;
}
.components-drop-zone__content-text{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
}
.components-dropdown{
display:inline-block;
}
.components-dropdown__content .components-popover__content{
padding:8px;
}
.components-dropdown__content .components-popover__content:has(.components-menu-group){
padding:0;
}
.components-dropdown__content .components-popover__content:has(.components-menu-group) .components-dropdown-menu__menu>.components-menu-item__button,.components-dropdown__content .components-popover__content:has(.components-menu-group)>.components-menu-item__button{
margin:8px;
width:auto;
}
.components-dropdown__content [role=menuitem]{
white-space:nowrap;
}
.components-dropdown__content .components-menu-group{
padding:8px;
}
.components-dropdown__content .components-menu-group+.components-menu-group{
border-top:1px solid #ccc;
padding:8px;
}
.components-dropdown__content.is-alternate .components-menu-group+.components-menu-group{
border-color:#1e1e1e;
}
.components-dropdown-menu__toggle{
vertical-align:top;
}
.components-dropdown-menu__menu{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
line-height:1.4;
width:100%;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item,.components-dropdown-menu__menu .components-menu-item{
cursor:pointer;
outline:none;
padding:6px;
white-space:nowrap;
width:100%;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator,.components-dropdown-menu__menu .components-menu-item.has-separator{
margin-top:6px;
overflow:visible;
position:relative;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator:before,.components-dropdown-menu__menu .components-menu-item.has-separator:before{
background-color:#ddd;
box-sizing:initial;
content:"";
display:block;
height:1px;
left:0;
position:absolute;
right:0;
top:-3px;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active svg,.components-dropdown-menu__menu .components-menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-menu-item.is-active svg{
background:#1e1e1e;
border-radius:1px;
box-shadow:0 0 0 1px #1e1e1e;
color:#fff;
}
.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-icon-only,.components-dropdown-menu__menu .components-menu-item.is-icon-only{
width:auto;
}
.components-dropdown-menu__menu .components-menu-item__button,.components-dropdown-menu__menu .components-menu-item__button.components-button{
height:auto;
min-height:40px;
padding-left:8px;
padding-right:8px;
text-align:left;
}
.components-duotone-picker__color-indicator:before{
background:#0000;
}
.components-duotone-picker__color-indicator>.components-button,.components-duotone-picker__color-indicator>.components-button.is-pressed:hover:not(:disabled){
background:linear-gradient(-45deg, #0000 48%, #ddd 0, #ddd 52%, #0000 0);
color:#0000;
}
.components-duotone-picker__color-indicator>.components-button:not([aria-disabled=true]):active{
color:#0000;
}
.components-color-list-picker,.components-color-list-picker__swatch-button{
width:100%;
}
.components-color-list-picker__color-picker{
margin:8px 0;
}
.components-color-list-picker__swatch-color{
margin:2px;
}
.components-external-link{
text-decoration:none;
}
.components-external-link__contents{
text-decoration:underline;
}
.components-external-link__icon{
font-weight:400;
margin-left:.5ch;
}
.components-form-toggle,.components-form-toggle .components-form-toggle__track{
display:inline-block;
height:16px;
position:relative;
}
.components-form-toggle .components-form-toggle__track{
background-color:#fff;
border:1px solid #949494;
border-radius:8px;
box-sizing:border-box;
content:"";
overflow:hidden;
vertical-align:top;
width:32px;
}
@media not (prefers-reduced-motion){
.components-form-toggle .components-form-toggle__track{
transition:background-color .2s ease,border-color .2s ease;
}
}
.components-form-toggle .components-form-toggle__track:after{
border-top:16px solid #0000;
box-sizing:border-box;
content:"";
inset:0;
opacity:0;
position:absolute;
}
@media not (prefers-reduced-motion){
.components-form-toggle .components-form-toggle__track:after{
transition:opacity .2s ease;
}
}
.components-form-toggle .components-form-toggle__thumb{
background-color:#1e1e1e;
border:6px solid #0000;
border-radius:50%;
box-shadow:0 1px 1px #00000008,0 1px 2px #00000005,0 3px 3px #00000005,0 4px 4px #00000003;
box-sizing:border-box;
display:block;
height:12px;
left:2px;
position:absolute;
top:2px;
width:12px;
}
@media not (prefers-reduced-motion){
.components-form-toggle .components-form-toggle__thumb{
transition:transform .2s ease,background-color .2s ease-out;
}
}
.components-form-toggle.is-checked .components-form-toggle__track{
background-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-form-toggle.is-checked .components-form-toggle__track:after{
opacity:1;
}
.components-form-toggle .components-form-toggle__input:focus+.components-form-toggle__track{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
outline-offset:2px;
}
.components-form-toggle.is-checked .components-form-toggle__thumb{
background-color:#fff;
border-width:0;
transform:translateX(16px);
}
.components-disabled .components-form-toggle,.components-form-toggle.is-disabled{
opacity:.3;
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]{
border:none;
height:100%;
left:0;
margin:0;
opacity:0;
padding:0;
position:absolute;
top:0;
width:100%;
z-index:1;
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]:checked{
background:none;
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]:before{
content:"";
}
.components-form-toggle input.components-form-toggle__input[type=checkbox]:not(:disabled,[aria-disabled=true]){
cursor:pointer;
}
.components-form-token-field__input-container{
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
cursor:text;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
line-height:normal;
padding:0;
width:100%;
}
@media not (prefers-reduced-motion){
.components-form-token-field__input-container{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-form-token-field__input-container{
font-size:13px;
line-height:normal;
}
}
.components-form-token-field__input-container:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-form-token-field__input-container::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-form-token-field__input-container::-moz-placeholder{
color:#1e1e1e9e;
}
.components-form-token-field__input-container:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-form-token-field__input-container.is-disabled{
background:#ddd;
border-color:#ddd;
}
.components-form-token-field__input-container.is-active{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-form-token-field__input-container input[type=text].components-form-token-field__input{
background:inherit;
border:0;
box-shadow:none;
color:#1e1e1e;
display:inline-block;
flex:1;
font-family:inherit;
font-size:16px;
margin-left:4px;
max-width:100%;
min-height:24px;
min-width:50px;
padding:0;
width:100%;
}
@media (min-width:600px){
.components-form-token-field__input-container input[type=text].components-form-token-field__input{
font-size:13px;
}
}
.components-form-token-field.is-active .components-form-token-field__input-container input[type=text].components-form-token-field__input,.components-form-token-field__input-container input[type=text].components-form-token-field__input:focus{
box-shadow:none;
outline:none;
}
.components-form-token-field__input-container .components-form-token-field__token+input[type=text].components-form-token-field__input{
width:auto;
}
.components-form-token-field__token{
color:#1e1e1e;
display:flex;
font-size:13px;
max-width:100%;
}
.components-form-token-field__token.is-success .components-form-token-field__remove-token,.components-form-token-field__token.is-success .components-form-token-field__token-text{
background:#4ab866;
}
.components-form-token-field__token.is-error .components-form-token-field__remove-token,.components-form-token-field__token.is-error .components-form-token-field__token-text{
background:#cc1818;
}
.components-form-token-field__token.is-validating .components-form-token-field__remove-token,.components-form-token-field__token.is-validating .components-form-token-field__token-text{
color:#757575;
}
.components-form-token-field__token.is-borderless{
padding:0 24px 0 0;
position:relative;
}
.components-form-token-field__token.is-borderless .components-form-token-field__token-text{
background:#0000;
}
.components-form-token-field__token.is-borderless:not(.is-disabled) .components-form-token-field__token-text{
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-form-token-field__token.is-borderless .components-form-token-field__remove-token{
background:#0000;
color:#757575;
position:absolute;
right:0;
top:1px;
}
.components-form-token-field__token.is-borderless.is-success .components-form-token-field__token-text{
color:#4ab866;
}
.components-form-token-field__token.is-borderless.is-error .components-form-token-field__token-text{
color:#cc1818;
padding:0 4px 0 6px;
}
.components-form-token-field__token.is-borderless.is-validating .components-form-token-field__token-text{
color:#1e1e1e;
}
.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{
background:#ddd;
display:inline-block;
height:auto;
min-width:unset;
}
@media not (prefers-reduced-motion){
.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{
transition:all .2s cubic-bezier(.4, 1, .4, 1);
}
}
.components-form-token-field__token-text{
border-radius:1px 0 0 1px;
line-height:24px;
overflow:hidden;
padding:0 0 0 8px;
text-overflow:ellipsis;
white-space:nowrap;
}
.components-form-token-field__remove-token.components-button{
border-radius:0 1px 1px 0;
color:#1e1e1e;
line-height:10px;
overflow:initial;
}
.components-form-token-field__remove-token.components-button:hover:not(:disabled){
color:#1e1e1e;
}
.components-form-token-field__suggestions-list{
box-shadow:inset 0 1px 0 0 #949494;
flex:1 0 100%;
list-style:none;
margin:0;
max-height:128px;
min-width:100%;
overflow-y:auto;
padding:0;
}
@media not (prefers-reduced-motion){
.components-form-token-field__suggestions-list{
transition:all .15s ease-in-out;
}
}
.components-form-token-field__suggestion{
box-sizing:border-box;
color:#1e1e1e;
display:block;
font-size:13px;
margin:0;
min-height:32px;
padding:8px 12px;
}
.components-form-token-field__suggestion.is-selected{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:#fff;
}
.components-form-token-field__suggestion[aria-disabled=true]{
color:#949494;
pointer-events:none;
}
.components-form-token-field__suggestion[aria-disabled=true].is-selected{
background-color:rgba(var(--wp-components-color-accent--rgb, var(--wp-admin-theme-color--rgb)), .04);
}
.components-form-token-field__suggestion:not(.is-empty){
cursor:pointer;
}
@media (min-width:600px){
.components-guide{
width:600px;
}
}
.components-guide .components-modal__content{
margin-top:0;
padding:0;
}
.components-guide .components-modal__content:before{
content:none;
}
.components-guide .components-modal__header{
border-bottom:none;
height:60px;
padding:0;
position:sticky;
}
.components-guide .components-modal__header .components-button{
align-self:flex-start;
margin:8px 8px 0 0;
position:static;
}
.components-guide .components-modal__header .components-button:hover svg{
fill:#fff;
}
.components-guide .components-guide__container{
display:flex;
flex-direction:column;
justify-content:space-between;
margin-top:-60px;
min-height:100%;
}
.components-guide .components-guide__page{
display:flex;
flex-direction:column;
justify-content:center;
position:relative;
}
@media (min-width:600px){
.components-guide .components-guide__page{
min-height:300px;
}
}
.components-guide .components-guide__footer{
align-content:center;
display:flex;
height:36px;
justify-content:center;
margin:0 0 24px;
padding:0 32px;
position:relative;
width:100%;
}
.components-guide .components-guide__page-control{
margin:0;
text-align:center;
}
.components-guide .components-guide__page-control li{
display:inline-block;
margin:0;
}
.components-guide .components-guide__page-control .components-button{
color:#e0e0e0;
margin:-6px 0;
}
.components-guide .components-guide__page-control li[aria-current=step] .components-button{
color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-modal__frame.components-guide{
border:none;
max-height:575px;
min-width:312px;
}
@media (max-width:600px){
.components-modal__frame.components-guide{
margin:auto;
max-width:calc(100vw - 32px);
}
}
.components-button.components-guide__back-button,.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{
position:absolute;
}
.components-button.components-guide__back-button{
left:32px;
}
.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{
right:32px;
}
[role=region]{
position:relative;
}
.is-focusing-regions [role=region]:focus:after,[role=region].interface-interface-skeleton__content:focus-visible:after{
bottom:0;
content:"";
left:0;
pointer-events:none;
position:absolute;
right:0;
top:0;
z-index:1000000;
}
.is-focusing-regions .editor-post-publish-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-entities-saved-states-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-publish-panel,.is-focusing-regions .interface-interface-skeleton__sidebar .editor-layout__toggle-sidebar-panel,.is-focusing-regions [role=region]:focus:after,.is-focusing-regions.is-distraction-free .interface-interface-skeleton__header .edit-post-header,[role=region].interface-interface-skeleton__content:focus-visible:after{
outline-color:var(--wp-admin-theme-color);
outline-offset:calc(((-1*var(--wp-admin-border-width-focus))/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2);
outline-style:solid;
outline-width:calc((var(--wp-admin-border-width-focus)/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2);
}
.components-menu-group+.components-menu-group{
border-top:1px solid #1e1e1e;
padding-top:8px;
}
.components-menu-group+.components-menu-group.has-hidden-separator{
border-top:none;
margin-top:0;
padding-top:0;
}
.components-menu-group:has(>div:empty){
display:none;
}
.components-menu-group__label{
color:#757575;
font-size:11px;
font-weight:500;
margin-bottom:12px;
margin-top:4px;
padding:0 8px;
text-transform:uppercase;
white-space:nowrap;
}
.components-menu-item__button,.components-menu-item__button.components-button{
width:100%;
}
.components-menu-item__button.components-button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button.components-button[role=menuitemradio] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemradio] .components-menu-item__item:only-child{
box-sizing:initial;
padding-right:48px;
}
.components-menu-item__button .components-menu-items__item-icon,.components-menu-item__button.components-button .components-menu-items__item-icon{
display:inline-block;
flex:0 0 auto;
}
.components-menu-item__button .components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-items__item-icon.has-icon-right{
margin-left:24px;
margin-right:-2px;
}
.components-menu-item__button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right{
margin-left:8px;
}
.components-menu-item__button .block-editor-block-icon,.components-menu-item__button.components-button .block-editor-block-icon{
margin-left:-2px;
margin-right:8px;
}
.components-menu-item__button.components-button.is-primary,.components-menu-item__button.is-primary{
justify-content:center;
}
.components-menu-item__button.components-button.is-primary .components-menu-item__item,.components-menu-item__button.is-primary .components-menu-item__item{
margin-right:0;
}
.components-menu-item__button.components-button:disabled.is-tertiary,.components-menu-item__button.components-button[aria-disabled=true].is-tertiary,.components-menu-item__button:disabled.is-tertiary,.components-menu-item__button[aria-disabled=true].is-tertiary{
background:none;
color:var(--wp-components-color-accent-darker-10, var(--wp-admin-theme-color-darker-10, #2145e6));
opacity:.3;
}
.components-menu-item__info-wrapper{
display:flex;
flex-direction:column;
margin-right:auto;
}
.components-menu-item__info{
color:#757575;
font-size:12px;
margin-top:4px;
white-space:normal;
}
.components-menu-item__item{
align-items:center;
display:inline-flex;
margin-right:auto;
min-width:160px;
white-space:nowrap;
}
.components-menu-item__shortcut{
align-self:center;
color:currentColor;
display:none;
margin-left:auto;
margin-right:0;
padding-left:24px;
}
@media (min-width:480px){
.components-menu-item__shortcut{
display:inline;
}
}
.components-menu-items-choice,.components-menu-items-choice.components-button{
height:auto;
min-height:40px;
}
.components-menu-items-choice svg,.components-menu-items-choice.components-button svg{
margin-right:12px;
}
.components-menu-items-choice.components-button.has-icon,.components-menu-items-choice.has-icon{
padding-left:12px;
}
.components-modal__screen-overlay{
background-color:#00000059;
bottom:0;
display:flex;
left:0;
position:fixed;
right:0;
top:0;
z-index:100000;
}
@keyframes __wp-base-styles-fade-in{
0%{
opacity:0;
}
to{
opacity:1;
}
}
@media not (prefers-reduced-motion){
.components-modal__screen-overlay{
animation:__wp-base-styles-fade-in .08s linear 0s;
animation-fill-mode:forwards;
}
}
@keyframes __wp-base-styles-fade-out{
0%{
opacity:1;
}
to{
opacity:0;
}
}
@media not (prefers-reduced-motion){
.components-modal__screen-overlay.is-animating-out{
animation:__wp-base-styles-fade-out .08s linear 80ms;
animation-fill-mode:forwards;
}
}
.components-modal__frame{
animation-fill-mode:forwards;
animation-name:components-modal__appear-animation;
animation-timing-function:cubic-bezier(.29, 0, 0, 1);
background:#fff;
border-radius:8px 8px 0 0;
box-shadow:0 5px 15px #00000014,0 15px 27px #00000012,0 30px 36px #0000000a,0 50px 43px #00000005;
box-sizing:border-box;
display:flex;
margin:40px 0 0;
overflow:hidden;
width:100%;
}
.components-modal__frame *,.components-modal__frame :after,.components-modal__frame :before{
box-sizing:inherit;
}
@media not (prefers-reduced-motion){
.components-modal__frame{
animation-duration:var(--modal-frame-animation-duration);
}
}
.components-modal__screen-overlay.is-animating-out .components-modal__frame{
animation-name:components-modal__disappear-animation;
animation-timing-function:cubic-bezier(1, 0, .2, 1);
}
@media (min-width:600px){
.components-modal__frame{
border-radius:8px;
margin:auto;
max-height:calc(100% - 120px);
max-width:calc(100% - 32px);
min-width:350px;
width:auto;
}
}
@media (min-width:600px) and (min-width:600px){
.components-modal__frame.is-full-screen{
height:calc(100% - 32px);
max-height:none;
width:calc(100% - 32px);
}
}
@media (min-width:600px) and (min-width:782px){
.components-modal__frame.is-full-screen{
height:calc(100% - 80px);
max-width:none;
width:calc(100% - 80px);
}
}
@media (min-width:600px){
.components-modal__frame.has-size-large,.components-modal__frame.has-size-medium,.components-modal__frame.has-size-small{
width:100%;
}
.components-modal__frame.has-size-small{
max-width:384px;
}
.components-modal__frame.has-size-medium{
max-width:512px;
}
.components-modal__frame.has-size-large{
max-width:840px;
}
}
@media (min-width:960px){
.components-modal__frame{
max-height:70%;
}
}
@keyframes components-modal__appear-animation{
0%{
opacity:0;
transform:scale(.9);
}
to{
opacity:1;
transform:scale(1);
}
}
@keyframes components-modal__disappear-animation{
0%{
opacity:1;
transform:scale(1);
}
to{
opacity:0;
transform:scale(.9);
}
}
.components-modal__header{
align-items:center;
border-bottom:1px solid #0000;
box-sizing:border-box;
display:flex;
flex-direction:row;
height:72px;
justify-content:space-between;
left:0;
padding:24px 32px 8px;
position:absolute;
top:0;
width:100%;
z-index:10;
}
.components-modal__header .components-modal__header-heading{
font-size:1.2rem;
font-weight:600;
}
.components-modal__header h1{
line-height:1;
margin:0;
}
.components-modal__content.has-scrolled-content:not(.hide-header) .components-modal__header{
border-bottom-color:#ddd;
}
.components-modal__header+p{
margin-top:0;
}
.components-modal__header-heading-container{
align-items:center;
display:flex;
flex-direction:row;
flex-grow:1;
justify-content:left;
}
.components-modal__header-icon-container{
display:inline-block;
}
.components-modal__header-icon-container svg{
max-height:36px;
max-width:36px;
padding:8px;
}
.components-modal__content{
flex:1;
margin-top:72px;
overflow:auto;
padding:4px 32px 32px;
}
.components-modal__content.hide-header{
margin-top:0;
padding-top:32px;
}
.components-modal__content.is-scrollable:focus-visible{
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
outline-offset:-2px;
}
.components-notice{
align-items:center;
background-color:#fff;
border-left:4px solid var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
color:#1e1e1e;
display:flex;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
padding:8px 12px;
}
.components-notice.is-dismissible{
position:relative;
}
.components-notice.is-success{
background-color:#eff9f1;
border-left-color:#4ab866;
}
.components-notice.is-warning{
background-color:#fef8ee;
border-left-color:#f0b849;
}
.components-notice.is-error{
background-color:#f4a2a2;
border-left-color:#cc1818;
}
.components-notice__content{
flex-grow:1;
margin:4px 25px 4px 0;
}
.components-notice__actions{
display:flex;
flex-wrap:wrap;
}
.components-notice__action.components-button{
margin-right:8px;
}
.components-notice__action.components-button,.components-notice__action.components-button.is-link{
margin-left:12px;
}
.components-notice__action.components-button.is-secondary{
vertical-align:initial;
}
.components-notice__dismiss{
align-self:flex-start;
color:#757575;
flex-shrink:0;
}
.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):focus,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):active,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{
background-color:initial;
color:#1e1e1e;
}
.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{
box-shadow:none;
}
.components-notice-list{
box-sizing:border-box;
max-width:100vw;
}
.components-notice-list .components-notice__content{
line-height:2;
margin-bottom:12px;
margin-top:12px;
}
.components-notice-list .components-notice__action.components-button{
display:block;
margin-left:0;
margin-top:8px;
}
.components-panel{
background:#fff;
border:1px solid #e0e0e0;
}
.components-panel>.components-panel__body:first-child,.components-panel>.components-panel__header:first-child{
margin-top:-1px;
}
.components-panel>.components-panel__body:last-child,.components-panel>.components-panel__header:last-child{
border-bottom-width:0;
}
.components-panel+.components-panel{
margin-top:-1px;
}
.components-panel__body{
border-bottom:1px solid #e0e0e0;
border-top:1px solid #e0e0e0;
}
.components-panel__body h3{
margin:0 0 .5em;
}
.components-panel__body.is-opened{
padding:16px;
}
.components-panel__header{
align-items:center;
border-bottom:1px solid #ddd;
box-sizing:initial;
display:flex;
flex-shrink:0;
height:47px;
justify-content:space-between;
padding:0 16px;
}
.components-panel__header h2{
color:inherit;
font-size:inherit;
margin:0;
}
.components-panel__body+.components-panel__body,.components-panel__body+.components-panel__header,.components-panel__header+.components-panel__body,.components-panel__header+.components-panel__header{
margin-top:-1px;
}
.components-panel__body>.components-panel__body-title{
display:block;
font-size:inherit;
margin-bottom:0;
margin-top:0;
padding:0;
}
@media not (prefers-reduced-motion){
.components-panel__body>.components-panel__body-title{
transition:background .1s ease-in-out;
}
}
.components-panel__body.is-opened>.components-panel__body-title{
margin:-16px -16px 5px;
}
.components-panel__body>.components-panel__body-title:hover{
background:#f0f0f0;
border:none;
}
.components-panel__body-toggle.components-button{
border:none;
box-shadow:none;
color:#1e1e1e;
font-weight:500;
height:auto;
outline:none;
padding:16px 48px 16px 16px;
position:relative;
text-align:left;
width:100%;
}
@media not (prefers-reduced-motion){
.components-panel__body-toggle.components-button{
transition:background .1s ease-in-out;
}
}
.components-panel__body-toggle.components-button:focus{
border-radius:0;
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-panel__body-toggle.components-button .components-panel__arrow{
color:#1e1e1e;
position:absolute;
right:16px;
top:50%;
transform:translateY(-50%);
fill:currentColor;
}
@media not (prefers-reduced-motion){
.components-panel__body-toggle.components-button .components-panel__arrow{
transition:color .1s ease-in-out;
}
}
body.rtl .components-panel__body-toggle.components-button .dashicons-arrow-right{
-ms-filter:fliph;
filter:FlipH;
margin-top:-10px;
transform:scaleX(-1);
}
.components-panel__icon{
color:#757575;
margin:-2px 0 -2px 6px;
}
.components-panel__body-toggle-icon{
margin-right:-5px;
}
.components-panel__color-title{
float:left;
height:19px;
}
.components-panel__row{
align-items:center;
display:flex;
justify-content:space-between;
margin-top:8px;
min-height:36px;
}
.components-panel__row select{
min-width:0;
}
.components-panel__row label{
flex-shrink:0;
margin-right:12px;
max-width:75%;
}
.components-panel__row:empty,.components-panel__row:first-of-type{
margin-top:0;
}
.components-panel .circle-picker{
padding-bottom:20px;
}
.components-placeholder.components-placeholder{
align-items:flex-start;
box-sizing:border-box;
color:#1e1e1e;
display:flex;
flex-direction:column;
font-size:13px;
gap:16px;
margin:0;
padding:24px;
position:relative;
text-align:left;
width:100%;
-moz-font-smoothing:subpixel-antialiased;
-webkit-font-smoothing:subpixel-antialiased;
background-color:#fff;
border-radius:2px;
box-shadow:inset 0 0 0 1px #1e1e1e;
outline:1px solid #0000;
}
.components-placeholder__error,.components-placeholder__fieldset,.components-placeholder__instructions,.components-placeholder__label{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
font-weight:400;
letter-spacing:normal;
line-height:normal;
text-transform:none;
}
.components-placeholder__label{
align-items:center;
display:flex;
font-weight:600;
}
.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{
margin-right:4px;
fill:currentColor;
}
@media (forced-colors:active){
.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{
fill:CanvasText;
}
}
.components-placeholder__label:empty{
display:none;
}
.components-placeholder__fieldset,.components-placeholder__fieldset form{
display:flex;
flex-direction:row;
flex-wrap:wrap;
gap:16px;
justify-content:flex-start;
width:100%;
}
.components-placeholder__fieldset form p,.components-placeholder__fieldset p{
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
}
.components-placeholder__fieldset.is-column-layout,.components-placeholder__fieldset.is-column-layout form{
flex-direction:column;
}
.components-placeholder__input[type=url]{
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
flex:1 1 auto;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
line-height:normal;
padding:6px 8px;
}
@media not (prefers-reduced-motion){
.components-placeholder__input[type=url]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-placeholder__input[type=url]{
font-size:13px;
line-height:normal;
}
}
.components-placeholder__input[type=url]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-placeholder__input[type=url]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-placeholder__input[type=url]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-placeholder__input[type=url]:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-placeholder__error{
gap:8px;
width:100%;
}
.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link{
margin-left:10px;
margin-right:10px;
}
.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link:last-child{
margin-right:0;
}
.components-placeholder.is-medium .components-placeholder__instructions,.components-placeholder.is-small .components-placeholder__instructions{
display:none;
}
.components-placeholder.is-medium .components-placeholder__fieldset,.components-placeholder.is-medium .components-placeholder__fieldset form,.components-placeholder.is-small .components-placeholder__fieldset,.components-placeholder.is-small .components-placeholder__fieldset form{
flex-direction:column;
}
.components-placeholder.is-medium .components-button,.components-placeholder.is-medium .components-placeholder__fieldset>*,.components-placeholder.is-small .components-button,.components-placeholder.is-small .components-placeholder__fieldset>*{
justify-content:center;
width:100%;
}
.components-placeholder.is-small{
padding:16px;
}
.components-placeholder.has-illustration{
-webkit-backdrop-filter:blur(100px);
backdrop-filter:blur(100px);
backface-visibility:hidden;
background-color:initial;
border-radius:0;
box-shadow:none;
color:inherit;
display:flex;
overflow:hidden;
}
.is-dark-theme .components-placeholder.has-illustration{
background-color:#0000001a;
}
.components-placeholder.has-illustration .components-placeholder__fieldset{
margin-left:0;
margin-right:0;
}
.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{
opacity:0;
pointer-events:none;
}
@media not (prefers-reduced-motion){
.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{
transition:opacity .1s linear;
}
}
.is-selected>.components-placeholder.has-illustration .components-button,.is-selected>.components-placeholder.has-illustration .components-placeholder__instructions,.is-selected>.components-placeholder.has-illustration .components-placeholder__label{
opacity:1;
pointer-events:auto;
}
.components-placeholder.has-illustration:before{
background:currentColor;
bottom:0;
content:"";
left:0;
opacity:.1;
pointer-events:none;
position:absolute;
right:0;
top:0;
}
.is-selected .components-placeholder.has-illustration{
overflow:auto;
}
.components-placeholder__preview{
display:flex;
justify-content:center;
}
.components-placeholder__illustration{
box-sizing:initial;
height:100%;
left:50%;
position:absolute;
top:50%;
transform:translate(-50%, -50%);
width:100%;
stroke:currentColor;
opacity:.25;
}
.components-popover{
box-sizing:border-box;
will-change:transform;
z-index:1000000;
}
.components-popover *,.components-popover :after,.components-popover :before{
box-sizing:inherit;
}
.components-popover.is-expanded{
bottom:0;
left:0;
position:fixed;
right:0;
top:0;
z-index:1000000 !important;
}
.components-popover__content{
background:#fff;
border-radius:4px;
box-shadow:0 0 0 1px #ccc,0 2px 3px #0000000d,0 4px 5px #0000000a,0 12px 12px #00000008,0 16px 16px #00000005;
box-sizing:border-box;
width:min-content;
}
.is-alternate .components-popover__content{
border-radius:2px;
box-shadow:0 0 0 1px #1e1e1e;
}
.is-unstyled .components-popover__content{
background:none;
border-radius:0;
box-shadow:none;
}
.components-popover.is-expanded .components-popover__content{
box-shadow:0 -1px 0 0 #ccc;
height:calc(100% - 48px);
overflow-y:visible;
position:static;
width:auto;
}
.components-popover.is-expanded.is-alternate .components-popover__content{
box-shadow:0 -1px 0 #1e1e1e;
}
.components-popover__header{
align-items:center;
background:#fff;
display:flex;
height:48px;
justify-content:space-between;
padding:0 8px 0 16px;
}
.components-popover__header-title{
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
width:100%;
}
.components-popover__close.components-button{
z-index:5;
}
.components-popover__arrow{
display:flex;
height:14px;
pointer-events:none;
position:absolute;
width:14px;
}
.components-popover__arrow:before{
background-color:#fff;
content:"";
height:2px;
left:1px;
position:absolute;
right:1px;
top:-1px;
}
.components-popover__arrow.is-top{
bottom:-14px !important;
transform:rotate(0);
}
.components-popover__arrow.is-right{
left:-14px !important;
transform:rotate(90deg);
}
.components-popover__arrow.is-bottom{
top:-14px !important;
transform:rotate(180deg);
}
.components-popover__arrow.is-left{
right:-14px !important;
transform:rotate(-90deg);
}
.components-popover__triangle{
display:block;
flex:1;
}
.components-popover__triangle-bg{
fill:#fff;
}
.components-popover__triangle-border{
fill:#0000;
stroke-width:1px;
stroke:#ccc;
}
.is-alternate .components-popover__triangle-border{
stroke:#1e1e1e;
}
.components-radio-control{
border:0;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
margin:0;
padding:0;
}
.components-radio-control__group-wrapper.has-help{
margin-block-end:12px;
}
.components-radio-control__option{
align-items:center;
column-gap:8px;
display:grid;
grid-template-columns:auto 1fr;
grid-template-rows:auto minmax(0, max-content);
}
.components-radio-control__input[type=radio]{
appearance:none;
border:1px solid #1e1e1e;
border-radius:2px;
border-radius:50%;
box-shadow:0 0 0 #0000;
cursor:pointer;
display:inline-flex;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
grid-column:1;
grid-row:1;
height:24px;
line-height:normal;
margin:0;
max-width:24px;
min-width:24px;
padding:0;
position:relative;
transition:none;
width:24px;
}
@media not (prefers-reduced-motion){
.components-radio-control__input[type=radio]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-radio-control__input[type=radio]{
font-size:13px;
line-height:normal;
}
}
.components-radio-control__input[type=radio]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
}
.components-radio-control__input[type=radio]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-radio-control__input[type=radio]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-radio-control__input[type=radio]:-ms-input-placeholder{
color:#1e1e1e9e;
}
@media (min-width:600px){
.components-radio-control__input[type=radio]{
height:16px;
max-width:16px;
min-width:16px;
width:16px;
}
}
.components-radio-control__input[type=radio]:checked:before{
background-color:#fff;
border:4px solid #fff;
box-sizing:inherit;
height:12px;
left:50%;
margin:0;
position:absolute;
top:50%;
transform:translate(-50%, -50%);
width:12px;
}
@media (min-width:600px){
.components-radio-control__input[type=radio]:checked:before{
height:8px;
width:8px;
}
}
.components-radio-control__input[type=radio]:focus{
box-shadow:0 0 0 2px #fff, 0 0 0 4px var(--wp-admin-theme-color);
}
.components-radio-control__input[type=radio]:checked{
background:var(--wp-admin-theme-color);
border:none;
}
.components-radio-control__input[type=radio]:focus{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);
outline:2px solid #0000;
outline-offset:2px;
}
.components-radio-control__input[type=radio]:checked{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-radio-control__input[type=radio]:checked:before{
border-radius:50%;
content:"";
}
.components-radio-control__label{
cursor:pointer;
grid-column:2;
grid-row:1;
line-height:24px;
}
@media (min-width:600px){
.components-radio-control__label{
line-height:16px;
}
}
.components-radio-control__option-description{
grid-column:2;
grid-row:2;
padding-block-start:4px;
}
.components-radio-control__option-description.components-radio-control__option-description{
margin-top:0;
}
.components-resizable-box__handle{
display:none;
height:23px;
width:23px;
z-index:2;
}
.components-resizable-box__container.has-show-handle .components-resizable-box__handle{
display:block;
}
.components-resizable-box__handle>div{
height:100%;
outline:none;
position:relative;
width:100%;
z-index:2;
}
.components-resizable-box__container>img{
width:inherit;
}
.components-resizable-box__handle:after{
background:#fff;
border-radius:50%;
box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)), 0 1px 1px #00000008, 0 1px 2px #00000005, 0 3px 3px #00000005, 0 4px 4px #00000003;
content:"";
cursor:inherit;
display:block;
height:15px;
outline:2px solid #0000;
position:absolute;
right:calc(50% - 8px);
top:calc(50% - 8px);
width:15px;
}
.components-resizable-box__side-handle:before{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-radius:9999px;
content:"";
cursor:inherit;
display:block;
height:3px;
opacity:0;
position:absolute;
right:calc(50% - 1px);
top:calc(50% - 1px);
width:3px;
}
@media not (prefers-reduced-motion){
.components-resizable-box__side-handle:before{
transition:transform .1s ease-in;
will-change:transform;
}
}
.components-resizable-box__corner-handle,.components-resizable-box__side-handle{
z-index:2;
}
.components-resizable-box__side-handle.components-resizable-box__handle-bottom,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:before,.components-resizable-box__side-handle.components-resizable-box__handle-top,.components-resizable-box__side-handle.components-resizable-box__handle-top:before{
border-left:0;
border-right:0;
left:0;
width:100%;
}
.components-resizable-box__side-handle.components-resizable-box__handle-left,.components-resizable-box__side-handle.components-resizable-box__handle-left:before,.components-resizable-box__side-handle.components-resizable-box__handle-right,.components-resizable-box__side-handle.components-resizable-box__handle-right:before{
border-bottom:0;
border-top:0;
height:100%;
top:0;
}
@media not (prefers-reduced-motion){
.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{
animation:components-resizable-box__top-bottom-animation .1s ease-out 0s;
animation-fill-mode:forwards;
}
.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before{
animation:components-resizable-box__left-right-animation .1s ease-out 0s;
animation-fill-mode:forwards;
}
}
@media not all and (min-resolution:0.001dpcm){
@supports (-webkit-appearance:none){
.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{
animation:none;
}
}
}
@keyframes components-resizable-box__top-bottom-animation{
0%{
opacity:0;
transform:scaleX(0);
}
to{
opacity:1;
transform:scaleX(1);
}
}
@keyframes components-resizable-box__left-right-animation{
0%{
opacity:0;
transform:scaleY(0);
}
to{
opacity:1;
transform:scaleY(1);
}
}
.components-resizable-box__handle-right{
right:-11.5px;
}
.components-resizable-box__handle-left{
left:-11.5px;
}
.components-resizable-box__handle-top{
top:-11.5px;
}
.components-resizable-box__handle-bottom{
bottom:-11.5px;
}
.components-responsive-wrapper{
align-items:center;
display:flex;
justify-content:center;
max-width:100%;
position:relative;
}
.components-responsive-wrapper__content{
display:block;
max-width:100%;
width:100%;
}
.components-sandbox{
overflow:hidden;
}
iframe.components-sandbox{
width:100%;
}
body.lockscroll,html.lockscroll{
overflow:hidden;
}
.components-select-control__input{
outline:0;
-webkit-tap-highlight-color:rgba(0, 0, 0, 0) !important;
}
@media (max-width:782px){
.components-base-control .components-base-control__field .components-select-control__input{
font-size:16px;
}
}
.components-snackbar{
-webkit-backdrop-filter:blur(16px) saturate(180%);
backdrop-filter:blur(16px) saturate(180%);
background:#000000d9;
border-radius:4px;
box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;
box-sizing:border-box;
color:#fff;
cursor:pointer;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
max-width:600px;
padding:12px 20px;
pointer-events:auto;
width:100%;
}
@media (min-width:600px){
.components-snackbar{
width:fit-content;
}
}
.components-snackbar:focus{
box-shadow:inset 0 0 0 1px #fff, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
}
.components-snackbar.components-snackbar-explicit-dismiss{
cursor:default;
}
.components-snackbar .components-snackbar__content-with-icon{
padding-left:24px;
position:relative;
}
.components-snackbar .components-snackbar__icon{
left:-8px;
position:absolute;
top:-2.9px;
}
.components-snackbar .components-snackbar__dismiss-button{
cursor:pointer;
margin-left:24px;
}
.components-snackbar__action.components-button{
color:#fff;
flex-shrink:0;
margin-left:32px;
}
.components-snackbar__action.components-button:focus{
box-shadow:none;
outline:1px dotted #fff;
}
.components-snackbar__action.components-button:hover{
color:currentColor;
text-decoration:none;
}
.components-snackbar__content{
align-items:baseline;
display:flex;
justify-content:space-between;
line-height:1.4;
}
.components-snackbar-list{
box-sizing:border-box;
pointer-events:none;
position:absolute;
width:100%;
z-index:100000;
}
.components-snackbar-list__notice-container{
padding-top:8px;
position:relative;
}
.components-tab-panel__tabs{
align-items:stretch;
display:flex;
flex-direction:row;
}
.components-tab-panel__tabs[aria-orientation=vertical]{
flex-direction:column;
}
.components-tab-panel__tabs-item{
background:#0000;
border:none;
border-radius:0;
box-shadow:none;
cursor:pointer;
font-weight:500;
height:48px !important;
margin-left:0;
padding:3px 16px;
position:relative;
}
.components-tab-panel__tabs-item:focus:not(:disabled){
box-shadow:none;
outline:none;
position:relative;
}
.components-tab-panel__tabs-item:after{
background:var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
border-radius:0;
bottom:0;
content:"";
height:calc(var(--wp-admin-border-width-focus)*0);
left:0;
pointer-events:none;
position:absolute;
right:0;
}
@media not (prefers-reduced-motion){
.components-tab-panel__tabs-item:after{
transition:all .1s linear;
}
}
.components-tab-panel__tabs-item.is-active:after{
height:calc(var(--wp-admin-border-width-focus)*1);
outline:2px solid #0000;
outline-offset:-1px;
}
.components-tab-panel__tabs-item:before{
border-radius:2px;
bottom:12px;
box-shadow:0 0 0 0 #0000;
content:"";
left:12px;
pointer-events:none;
position:absolute;
right:12px;
top:12px;
}
@media not (prefers-reduced-motion){
.components-tab-panel__tabs-item:before{
transition:all .1s linear;
}
}
.components-tab-panel__tabs-item:focus-visible:before{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
}
.components-tab-panel__tab-content:focus{
box-shadow:none;
outline:none;
}
.components-tab-panel__tab-content:focus-visible{
box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
outline:2px solid #0000;
outline-offset:0;
}
.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{
border:1px solid #949494;
border-radius:2px;
box-shadow:0 0 0 #0000;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:16px;
height:32px;
line-height:normal;
margin:0;
padding:6px 8px;
width:100%;
}
@media not (prefers-reduced-motion){
.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{
transition:box-shadow .1s linear;
}
}
@media (min-width:600px){
.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{
font-size:13px;
line-height:normal;
}
}
.components-text-control__input:focus,.components-text-control__input[type=color]:focus,.components-text-control__input[type=date]:focus,.components-text-control__input[type=datetime-local]:focus,.components-text-control__input[type=datetime]:focus,.components-text-control__input[type=email]:focus,.components-text-control__input[type=month]:focus,.components-text-control__input[type=number]:focus,.components-text-control__input[type=password]:focus,.components-text-control__input[type=tel]:focus,.components-text-control__input[type=text]:focus,.components-text-control__input[type=time]:focus,.components-text-control__input[type=url]:focus,.components-text-control__input[type=week]:focus{
border-color:var(--wp-admin-theme-color);
box-shadow:0 0 0 .5px var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-text-control__input::-webkit-input-placeholder,.components-text-control__input[type=color]::-webkit-input-placeholder,.components-text-control__input[type=date]::-webkit-input-placeholder,.components-text-control__input[type=datetime-local]::-webkit-input-placeholder,.components-text-control__input[type=datetime]::-webkit-input-placeholder,.components-text-control__input[type=email]::-webkit-input-placeholder,.components-text-control__input[type=month]::-webkit-input-placeholder,.components-text-control__input[type=number]::-webkit-input-placeholder,.components-text-control__input[type=password]::-webkit-input-placeholder,.components-text-control__input[type=tel]::-webkit-input-placeholder,.components-text-control__input[type=text]::-webkit-input-placeholder,.components-text-control__input[type=time]::-webkit-input-placeholder,.components-text-control__input[type=url]::-webkit-input-placeholder,.components-text-control__input[type=week]::-webkit-input-placeholder{
color:#1e1e1e9e;
}
.components-text-control__input::-moz-placeholder,.components-text-control__input[type=color]::-moz-placeholder,.components-text-control__input[type=date]::-moz-placeholder,.components-text-control__input[type=datetime-local]::-moz-placeholder,.components-text-control__input[type=datetime]::-moz-placeholder,.components-text-control__input[type=email]::-moz-placeholder,.components-text-control__input[type=month]::-moz-placeholder,.components-text-control__input[type=number]::-moz-placeholder,.components-text-control__input[type=password]::-moz-placeholder,.components-text-control__input[type=tel]::-moz-placeholder,.components-text-control__input[type=text]::-moz-placeholder,.components-text-control__input[type=time]::-moz-placeholder,.components-text-control__input[type=url]::-moz-placeholder,.components-text-control__input[type=week]::-moz-placeholder{
color:#1e1e1e9e;
}
.components-text-control__input:-ms-input-placeholder,.components-text-control__input[type=color]:-ms-input-placeholder,.components-text-control__input[type=date]:-ms-input-placeholder,.components-text-control__input[type=datetime-local]:-ms-input-placeholder,.components-text-control__input[type=datetime]:-ms-input-placeholder,.components-text-control__input[type=email]:-ms-input-placeholder,.components-text-control__input[type=month]:-ms-input-placeholder,.components-text-control__input[type=number]:-ms-input-placeholder,.components-text-control__input[type=password]:-ms-input-placeholder,.components-text-control__input[type=tel]:-ms-input-placeholder,.components-text-control__input[type=text]:-ms-input-placeholder,.components-text-control__input[type=time]:-ms-input-placeholder,.components-text-control__input[type=url]:-ms-input-placeholder,.components-text-control__input[type=week]:-ms-input-placeholder{
color:#1e1e1e9e;
}
.components-text-control__input.is-next-40px-default-size,.components-text-control__input[type=color].is-next-40px-default-size,.components-text-control__input[type=date].is-next-40px-default-size,.components-text-control__input[type=datetime-local].is-next-40px-default-size,.components-text-control__input[type=datetime].is-next-40px-default-size,.components-text-control__input[type=email].is-next-40px-default-size,.components-text-control__input[type=month].is-next-40px-default-size,.components-text-control__input[type=number].is-next-40px-default-size,.components-text-control__input[type=password].is-next-40px-default-size,.components-text-control__input[type=tel].is-next-40px-default-size,.components-text-control__input[type=text].is-next-40px-default-size,.components-text-control__input[type=time].is-next-40px-default-size,.components-text-control__input[type=url].is-next-40px-default-size,.components-text-control__input[type=week].is-next-40px-default-size{
height:40px;
padding-left:12px;
padding-right:12px;
}
.components-text-control__input[type=email],.components-text-control__input[type=url]{
direction:ltr;
}
.components-tip{
color:#757575;
display:flex;
}
.components-tip svg{
align-self:center;
fill:#f0b849;
flex-shrink:0;
margin-right:16px;
}
.components-tip p{
margin:0;
}
.components-toggle-control__label{
line-height:16px;
}
.components-toggle-control__label:not(.is-disabled){
cursor:pointer;
}
.components-toggle-control__help{
display:inline-block;
margin-inline-start:40px;
}
.components-accessible-toolbar{
border:1px solid #1e1e1e;
border-radius:2px;
display:inline-flex;
flex-shrink:0;
}
.components-accessible-toolbar>.components-toolbar-group:last-child{
border-right:none;
}
.components-accessible-toolbar.is-unstyled{
border:none;
}
.components-accessible-toolbar.is-unstyled>.components-toolbar-group{
border-right:none;
}
.components-accessible-toolbar[aria-orientation=vertical],.components-toolbar[aria-orientation=vertical]{
align-items:center;
display:flex;
flex-direction:column;
}
.components-accessible-toolbar .components-button,.components-toolbar .components-button{
height:48px;
padding-left:16px;
padding-right:16px;
position:relative;
z-index:1;
}
.components-accessible-toolbar .components-button:focus:not(:disabled),.components-toolbar .components-button:focus:not(:disabled){
box-shadow:none;
outline:none;
}
.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{
border-radius:2px;
content:"";
display:block;
height:32px;
left:8px;
position:absolute;
right:8px;
z-index:-1;
}
@media not (prefers-reduced-motion){
.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{
animation:components-button__appear-animation .1s ease;
animation-fill-mode:forwards;
}
}
.components-accessible-toolbar .components-button svg,.components-toolbar .components-button svg{
margin-left:auto;
margin-right:auto;
position:relative;
}
.components-accessible-toolbar .components-button.is-pressed,.components-accessible-toolbar .components-button.is-pressed:hover,.components-toolbar .components-button.is-pressed,.components-toolbar .components-button.is-pressed:hover{
background:#0000;
}
.components-accessible-toolbar .components-button.is-pressed:before,.components-toolbar .components-button.is-pressed:before{
background:#1e1e1e;
}
.components-accessible-toolbar .components-button:focus:before,.components-toolbar .components-button:focus:before{
box-shadow:inset 0 0 0 1px #fff, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
outline:2px solid #0000;
}
.components-accessible-toolbar .components-button.has-icon.has-icon,.components-toolbar .components-button.has-icon.has-icon{
min-width:48px;
padding-left:8px;
padding-right:8px;
}
@keyframes components-button__appear-animation{
0%{
transform:scaleY(0);
}
to{
transform:scaleY(1);
}
}
.components-toolbar__control.components-button{
position:relative;
}
.components-toolbar__control.components-button[data-subscript] svg{
padding:5px 10px 5px 0;
}
.components-toolbar__control.components-button[data-subscript]:after{
bottom:10px;
content:attr(data-subscript);
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:13px;
font-weight:600;
line-height:12px;
position:absolute;
right:8px;
}
.components-toolbar__control.components-button:not(:disabled).is-pressed[data-subscript]:after{
color:#fff;
}
.components-toolbar-group{
background-color:#fff;
border-right:1px solid #1e1e1e;
display:inline-flex;
flex-shrink:0;
flex-wrap:wrap;
line-height:0;
min-height:48px;
padding-left:6px;
padding-right:6px;
}
.components-toolbar-group .components-toolbar-group.components-toolbar-group{
border-width:0;
margin:0;
}
.components-toolbar-group .components-button.components-button,.components-toolbar-group .components-button.has-icon.has-icon{
justify-content:center;
min-width:36px;
padding-left:6px;
padding-right:6px;
}
.components-toolbar-group .components-button.components-button svg,.components-toolbar-group .components-button.has-icon.has-icon svg{
min-width:24px;
}
.components-toolbar-group .components-button.components-button:before,.components-toolbar-group .components-button.has-icon.has-icon:before{
left:2px;
right:2px;
}
.components-toolbar{
background-color:#fff;
border:1px solid #1e1e1e;
display:inline-flex;
flex-shrink:0;
flex-wrap:wrap;
margin:0;
min-height:48px;
}
.components-toolbar .components-toolbar.components-toolbar{
border-width:0;
margin:0;
}
div.components-toolbar>div{
display:flex;
margin:0;
}
div.components-toolbar>div+div.has-left-divider{
margin-left:6px;
overflow:visible;
position:relative;
}
div.components-toolbar>div+div.has-left-divider:before{
background-color:#ddd;
box-sizing:initial;
content:"";
display:inline-block;
height:20px;
left:-3px;
position:absolute;
top:8px;
width:1px;
}
.components-tooltip{
background:#000;
border-radius:2px;
box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;
color:#f0f0f0;
font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
font-size:12px;
line-height:1.4;
padding:4px 8px;
text-align:center;
z-index:1000002;
}
.components-tooltip__shortcut{
margin-left:8px;
}@charset "UTF-8";:root{--wp-admin-theme-color:#3858e9;--wp-admin-theme-color--rgb:56,88,233;--wp-admin-theme-color-darker-10:#2145e6;--wp-admin-theme-color-darker-10--rgb:33,69,230;--wp-admin-theme-color-darker-20:#183ad6;--wp-admin-theme-color-darker-20--rgb:24,58,214;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}@media not (prefers-reduced-motion){.components-animate__appear{animation:components-animate__appear-animation .1s cubic-bezier(0,0,.2,1) 0s;animation-fill-mode:forwards}}.components-animate__appear.is-from-top,.components-animate__appear.is-from-top.is-from-left{transform-origin:top left}.components-animate__appear.is-from-top.is-from-right{transform-origin:top right}.components-animate__appear.is-from-bottom,.components-animate__appear.is-from-bottom.is-from-left{transform-origin:bottom left}.components-animate__appear.is-from-bottom.is-from-right{transform-origin:bottom right}@keyframes components-animate__appear-animation{0%{transform:translateY(-2em) scaleY(0) scaleX(0)}to{transform:translateY(0) scaleY(1) scaleX(1)}}@media not (prefers-reduced-motion){.components-animate__slide-in{animation:components-animate__slide-in-animation .1s cubic-bezier(0,0,.2,1);animation-fill-mode:forwards}.components-animate__slide-in.is-from-left{transform:translateX(100%)}.components-animate__slide-in.is-from-right{transform:translateX(-100%)}}@keyframes components-animate__slide-in-animation{to{transform:translateX(0)}}@media not (prefers-reduced-motion){.components-animate__loading{animation:components-animate__loading 1.6s ease-in-out infinite}}@keyframes components-animate__loading{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.components-autocomplete__popover .components-popover__content{min-width:200px;padding:8px}.components-autocomplete__result.components-button{display:flex;height:auto;min-height:36px;text-align:left;width:100%}.components-autocomplete__result.components-button:focus:not(:disabled){box-shadow:inset 0 0 0 1px #fff,0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);outline:2px solid #0000}.components-badge{align-items:center;background-color:color-mix(in srgb,#fff 90%,var(--base-color));border-radius:2px;box-sizing:border-box;color:color-mix(in srgb,#000 50%,var(--base-color));display:inline-flex;font-size:12px;font-weight:400;gap:2px;line-height:20px;max-width:100%;min-height:24px;padding:0 8px}.components-badge *,.components-badge :after,.components-badge :before{box-sizing:inherit}.components-badge:where(.is-default){background-color:#f0f0f0;color:#2f2f2f}.components-badge.has-icon{padding-inline-start:4px}.components-badge.is-info{--base-color:#3858e9}.components-badge.is-warning{--base-color:#f0b849}.components-badge.is-error{--base-color:#cc1818}.components-badge.is-success{--base-color:#4ab866}.components-badge__icon{flex-shrink:0}.components-badge__content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.components-button-group{display:inline-block}.components-button-group .components-button{border-radius:0;box-shadow:inset 0 0 0 1px #1e1e1e;color:#1e1e1e;display:inline-flex}.components-button-group .components-button+.components-button{margin-left:-1px}.components-button-group .components-button:first-child{border-radius:2px 0 0 2px}.components-button-group .components-button:last-child{border-radius:0 2px 2px 0}.components-button-group .components-button.is-primary,.components-button-group .components-button:focus{position:relative;z-index:1}.components-button-group .components-button.is-primary{box-shadow:inset 0 0 0 1px #1e1e1e}.components-button{align-items:center;-webkit-appearance:none;background:none;border:0;border-radius:2px;box-sizing:border-box;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;height:36px;margin:0;padding:6px 12px;text-decoration:none}@media not (prefers-reduced-motion){.components-button{transition:box-shadow .1s linear}}.components-button.is-next-40px-default-size{height:40px}.components-button:hover:not(:disabled,[aria-disabled=true]),.components-button[aria-expanded=true]{color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button:focus:not(:disabled){box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:3px solid #0000}.components-button.is-primary{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:var(--wp-components-color-accent-inverted,#fff);outline:1px solid #0000;text-decoration:none;text-shadow:none;white-space:nowrap}.components-button.is-primary:hover:not(:disabled){background:var(--wp-components-color-accent-darker-10,var(--wp-admin-theme-color-darker-10,#2145e6));color:var(--wp-components-color-accent-inverted,#fff)}.components-button.is-primary:active:not(:disabled){background:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6));border-color:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6));color:var(--wp-components-color-accent-inverted,#fff)}.components-button.is-primary:focus:not(:disabled){box-shadow:inset 0 0 0 1px var(--wp-components-color-background,#fff),0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button.is-primary:disabled,.components-button.is-primary:disabled:active:enabled,.components-button.is-primary[aria-disabled=true],.components-button.is-primary[aria-disabled=true]:active:enabled,.components-button.is-primary[aria-disabled=true]:enabled{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:#fff6;outline:none}.components-button.is-primary:disabled:active:enabled:focus:enabled,.components-button.is-primary:disabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:active:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:focus:enabled{box-shadow:inset 0 0 0 1px var(--wp-components-color-background,#fff),0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button.is-primary.is-busy,.components-button.is-primary.is-busy:disabled,.components-button.is-primary.is-busy[aria-disabled=true]{background-image:linear-gradient(-45deg,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 33%,var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6)) 33%,var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6)) 70%,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 70%);background-size:100px 100%;border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:var(--wp-components-color-accent-inverted,#fff)}.components-button.is-secondary,.components-button.is-tertiary{outline:1px solid #0000}.components-button.is-secondary:active:not(:disabled),.components-button.is-tertiary:active:not(:disabled){box-shadow:none}.components-button.is-secondary:disabled,.components-button.is-secondary[aria-disabled=true],.components-button.is-secondary[aria-disabled=true]:hover,.components-button.is-tertiary:disabled,.components-button.is-tertiary[aria-disabled=true],.components-button.is-tertiary[aria-disabled=true]:hover{background:#0000;color:#949494;transform:none}.components-button.is-secondary{background:#0000;box-shadow:inset 0 0 0 1px var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),0 0 0 currentColor;color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:1px solid #0000;white-space:nowrap}.components-button.is-secondary:hover:not(:disabled,[aria-disabled=true],.is-pressed){background:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 4%,#0000);box-shadow:inset 0 0 0 1px var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6));color:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6))}.components-button.is-secondary:disabled:not(:focus),.components-button.is-secondary[aria-disabled=true]:hover:not(:focus),.components-button.is-secondary[aria-disabled=true]:not(:focus){box-shadow:inset 0 0 0 1px #ddd}.components-button.is-secondary:focus:not(:disabled){box-shadow:0 0 0 currentColor inset,0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button.is-tertiary{background:#0000;color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));white-space:nowrap}.components-button.is-tertiary:hover:not(:disabled,[aria-disabled=true],.is-pressed){background:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 4%,#0000);color:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6))}.components-button.is-tertiary:active:not(:disabled,[aria-disabled=true]){background:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 8%,#0000)}p+.components-button.is-tertiary{margin-left:-6px}.components-button.is-tertiary:disabled:not(:focus),.components-button.is-tertiary[aria-disabled=true]:hover:not(:focus),.components-button.is-tertiary[aria-disabled=true]:not(:focus){box-shadow:none;outline:none}.components-button.is-destructive{--wp-components-color-accent:#cc1818;--wp-components-color-accent-darker-10:#9e1313;--wp-components-color-accent-darker-20:#710d0d}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link){color:#cc1818}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):hover:not(:disabled,[aria-disabled=true]){color:#710d0d}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):focus{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #cc1818}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):active:not(:disabled,[aria-disabled=true]){background:#ccc}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):disabled,.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link)[aria-disabled=true]{color:#949494}.components-button.is-destructive.is-secondary:hover:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:hover:not(:disabled,[aria-disabled=true]){background:#cc18180a}.components-button.is-destructive.is-secondary:active:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:active:not(:disabled,[aria-disabled=true]){background:#cc181814}.components-button.is-link{background:none;border:0;border-radius:0;box-shadow:none;color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));height:auto;margin:0;outline:none;padding:0;text-align:left;text-decoration:underline}@media not (prefers-reduced-motion){.components-button.is-link{transition-duration:.05s;transition-property:border,background,color;transition-timing-function:ease-in-out}}.components-button.is-link:focus{border-radius:2px}.components-button.is-link:disabled,.components-button.is-link[aria-disabled=true]{color:#949494}.components-button:not(:disabled,[aria-disabled=true]):active{color:var(--wp-components-color-foreground,#1e1e1e)}.components-button:disabled,.components-button[aria-disabled=true]{color:#949494;cursor:default}.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{background-image:linear-gradient(-45deg,#fafafa 33%,#e0e0e0 0,#e0e0e0 70%,#fafafa 0);background-size:100px 100%}@media not (prefers-reduced-motion){.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{animation:components-button__busy-animation 2.5s linear infinite}}.components-button.is-compact{height:32px}.components-button.is-compact.has-icon:not(.has-text){min-width:32px;padding:0;width:32px}.components-button.is-small{font-size:11px;height:24px;line-height:22px;padding:0 8px}.components-button.is-small.has-icon:not(.has-text){min-width:24px;padding:0;width:24px}.components-button.has-icon{justify-content:center;min-width:36px;padding:6px}.components-button.has-icon.is-next-40px-default-size{min-width:40px}.components-button.has-icon .dashicon{align-items:center;box-sizing:initial;display:inline-flex;justify-content:center;padding:2px}.components-button.has-icon.has-text{gap:4px;justify-content:start;padding-left:8px;padding-right:12px}.components-button.is-pressed,.components-button.is-pressed:hover{color:var(--wp-components-color-foreground-inverted,#fff)}.components-button.is-pressed:hover:not(:disabled,[aria-disabled=true]),.components-button.is-pressed:not(:disabled,[aria-disabled=true]){background:var(--wp-components-color-foreground,#1e1e1e)}.components-button.is-pressed:disabled,.components-button.is-pressed[aria-disabled=true]{color:#949494}.components-button.is-pressed:disabled:not(.is-primary):not(.is-secondary):not(.is-tertiary),.components-button.is-pressed[aria-disabled=true]:not(.is-primary):not(.is-secondary):not(.is-tertiary){background:#949494;color:var(--wp-components-color-foreground-inverted,#fff)}.components-button.is-pressed:focus:not(:disabled){box-shadow:inset 0 0 0 1px var(--wp-components-color-background,#fff),0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000}.components-button svg{fill:currentColor;outline:none}@media (forced-colors:active){.components-button svg{fill:CanvasText}}.components-button .components-visually-hidden{height:auto}@keyframes components-button__busy-animation{0%{background-position:200px 0}}.components-checkbox-control{--checkbox-input-size:24px;--checkbox-input-margin:8px}@media (min-width:600px){.components-checkbox-control{--checkbox-input-size:16px}}.components-checkbox-control__label{cursor:pointer;line-height:var(--checkbox-input-size)}.components-checkbox-control__input[type=checkbox]{appearance:none;background:#fff;border:1px solid #1e1e1e;border-radius:2px;box-shadow:0 0 0 #0000;clear:none;color:#1e1e1e;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;height:var(--checkbox-input-size);line-height:normal;line-height:0;margin:0 4px 0 0;outline:0;padding:6px 8px;padding:0!important;text-align:center;transition:none;vertical-align:top;width:var(--checkbox-input-size)}@media not (prefers-reduced-motion){.components-checkbox-control__input[type=checkbox]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-checkbox-control__input[type=checkbox]{font-size:13px;line-height:normal}}.components-checkbox-control__input[type=checkbox]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox]::-webkit-input-placeholder{color:#1e1e1e9e}.components-checkbox-control__input[type=checkbox]::-moz-placeholder{color:#1e1e1e9e}.components-checkbox-control__input[type=checkbox]:-ms-input-placeholder{color:#1e1e1e9e}.components-checkbox-control__input[type=checkbox]:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox]:checked{background:var(--wp-admin-theme-color);border-color:var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox]:checked::-ms-check{opacity:0}.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{color:#fff;margin:-3px -5px}@media (min-width:782px){.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{margin:-4px 0 0 -5px}}.components-checkbox-control__input[type=checkbox][aria-checked=mixed]{background:var(--wp-admin-theme-color);border-color:var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{content:"\f460";display:inline-block;float:left;font:normal 30px/1 dashicons;vertical-align:middle;width:16px;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (min-width:782px){.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{float:none;font-size:21px}}.components-checkbox-control__input[type=checkbox]:disabled,.components-checkbox-control__input[type=checkbox][aria-disabled=true]{background:#f0f0f0;border-color:#ddd;cursor:default;opacity:1}@media not (prefers-reduced-motion){.components-checkbox-control__input[type=checkbox]{transition:border-color .1s ease-in-out}}.components-checkbox-control__input[type=checkbox]:focus{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);outline:2px solid #0000;outline-offset:2px}.components-checkbox-control__input[type=checkbox]:checked,.components-checkbox-control__input[type=checkbox]:indeterminate{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-checkbox-control__input[type=checkbox]:checked::-ms-check,.components-checkbox-control__input[type=checkbox]:indeterminate::-ms-check{opacity:0}.components-checkbox-control__input[type=checkbox]:checked:before{content:none}.components-checkbox-control__input-container{aspect-ratio:1;display:inline-block;flex-shrink:0;line-height:1;margin-right:var(--checkbox-input-margin);position:relative;vertical-align:middle;width:var(--checkbox-input-size)}svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{--checkmark-size:var(--checkbox-input-size);fill:#fff;cursor:pointer;height:var(--checkmark-size);left:50%;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);-webkit-user-select:none;user-select:none;width:var(--checkmark-size)}@media (min-width:600px){svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{--checkmark-size:calc(var(--checkbox-input-size) + 4px)}}.components-checkbox-control__help{display:inline-block;margin-inline-start:calc(var(--checkbox-input-size) + var(--checkbox-input-margin))}.components-circular-option-picker{display:inline-block;min-width:188px;width:100%}.components-circular-option-picker .components-circular-option-picker__custom-clear-wrapper{display:flex;justify-content:flex-end;margin-top:12px}.components-circular-option-picker .components-circular-option-picker__swatches{display:flex;flex-wrap:wrap;gap:12px;position:relative;z-index:1}.components-circular-option-picker>:not(.components-circular-option-picker__swatches){position:relative;z-index:0}.components-circular-option-picker__option-wrapper{display:inline-block;height:28px;transform:scale(1);vertical-align:top;width:28px}@media not (prefers-reduced-motion){.components-circular-option-picker__option-wrapper{transition:transform .1s ease;will-change:transform}}.components-circular-option-picker__option-wrapper:hover{transform:scale(1.2)}.components-circular-option-picker__option-wrapper>div{height:100%;width:100%}.components-circular-option-picker__option-wrapper:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' fill='none'%3E%3Cpath fill='%23555D65' d='M6 8V6H4v2zm2 0V6h2v2zm2 8H8v-2h2zm2 0v-2h2v2zm0 2v-2h-2v2H8v2h2v-2zm2 0v2h-2v-2zm2 0h-2v-2h2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M18 18h2v-2h-2v-2h2v-2h-2v-2h2V8h-2v2h-2V8h-2v2h2v2h-2v2h2v2h2zm-2-4v-2h2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' d='M18 18v2h-2v-2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M8 10V8H6v2H4v2h2v2H4v2h2v2H4v2h2v2H4v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2v2h-2V4h-2v2h-2V4h-2v2h-2V4h-2v2h2v2h-2v2zm0 2v-2H6v2zm2 0v-2h2v2zm0 2v-2H8v2H6v2h2v2H6v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h-2v2h-2V6h-2v2h-2v2h2v2h-2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M4 0H2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2H8V0H6v2H4zm0 4V2H2v2zm2 0V2h2v2zm0 2V4H4v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2H8v2z' clip-rule='evenodd'/%3E%3C/svg%3E");border-radius:50%;bottom:1px;content:"";left:1px;position:absolute;right:1px;top:1px;z-index:-1}.components-circular-option-picker__option{aspect-ratio:1;background:#0000;border:none;border-radius:50%;box-shadow:inset 0 0 0 14px;cursor:pointer;display:inline-block;height:100%!important;vertical-align:top}@media not (prefers-reduced-motion){.components-circular-option-picker__option{transition:box-shadow .1s ease}}.components-circular-option-picker__option:hover{box-shadow:inset 0 0 0 14px!important}.components-circular-option-picker__option[aria-pressed=true],.components-circular-option-picker__option[aria-selected=true]{box-shadow:inset 0 0 0 4px;overflow:visible;position:relative;z-index:1}.components-circular-option-picker__option[aria-pressed=true]+svg,.components-circular-option-picker__option[aria-selected=true]+svg{border-radius:50%;left:2px;pointer-events:none;position:absolute;top:2px;z-index:2}.components-circular-option-picker__option:after{border:1px solid #0000;border-radius:50%;bottom:-1px;box-shadow:inset 0 0 0 1px #0003;box-sizing:inherit;content:"";left:-1px;position:absolute;right:-1px;top:-1px}.components-circular-option-picker__option:focus:after{border:2px solid #757575;border-radius:50%;box-shadow:inset 0 0 0 2px #fff;content:"";height:calc(100% + 4px);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:calc(100% + 4px)}.components-circular-option-picker__option.components-button:focus{background-color:initial;box-shadow:inset 0 0 0 14px;outline:none}.components-circular-option-picker__button-action .components-circular-option-picker__option{background:#fff;color:#fff}.components-circular-option-picker__dropdown-link-action{margin-right:16px}.components-circular-option-picker__dropdown-link-action .components-button{line-height:22px}.components-palette-edit__popover-gradient-picker{padding:8px;width:260px}.components-dropdown-menu__menu .components-palette-edit__menu-button{width:100%}.component-color-indicator{background:#fff linear-gradient(-45deg,#0000 48%,#ddd 0,#ddd 52%,#0000 0);border-radius:50%;box-shadow:inset 0 0 0 1px #0003;display:inline-block;height:20px;padding:0;width:20px}.components-combobox-control{width:100%}input.components-combobox-control__input[type=text]{border:none;box-shadow:none;font-family:inherit;font-size:16px;line-height:inherit;margin:0;min-height:auto;padding:2px;width:100%}@media (min-width:600px){input.components-combobox-control__input[type=text]{font-size:13px}}input.components-combobox-control__input[type=text]:focus{box-shadow:none;outline:none}.components-combobox-control__suggestions-container{align-items:flex-start;border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;display:flex;flex-wrap:wrap;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;line-height:normal;padding:0;width:100%}@media not (prefers-reduced-motion){.components-combobox-control__suggestions-container{transition:box-shadow .1s linear}}@media (min-width:600px){.components-combobox-control__suggestions-container{font-size:13px;line-height:normal}}.components-combobox-control__suggestions-container:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-combobox-control__suggestions-container::-webkit-input-placeholder{color:#1e1e1e9e}.components-combobox-control__suggestions-container::-moz-placeholder{color:#1e1e1e9e}.components-combobox-control__suggestions-container:-ms-input-placeholder{color:#1e1e1e9e}.components-combobox-control__suggestions-container:focus-within{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-combobox-control__suggestions-container .components-spinner{margin:0}.components-color-palette__custom-color-wrapper{position:relative;z-index:0}.components-color-palette__custom-color-button{background:none;border:none;border-radius:4px 4px 0 0;box-shadow:inset 0 0 0 1px #0003;box-sizing:border-box;cursor:pointer;height:64px;outline:1px solid #0000;position:relative;width:100%}.components-color-palette__custom-color-button:focus{box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline-width:2px}.components-color-palette__custom-color-button:after{background-image:repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0),repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0);background-position:0 0,24px 24px;background-size:48px 48px;border-radius:3px 3px 0 0;content:"";inset:1px;position:absolute;z-index:-1}.components-color-palette__custom-color-text-wrapper{border-radius:0 0 4px 4px;box-shadow:inset 0 -1px 0 0 #0003,inset 1px 0 0 0 #0003,inset -1px 0 0 0 #0003;font-size:13px;padding:12px 16px;position:relative}.components-color-palette__custom-color-name{color:var(--wp-components-color-foreground,#1e1e1e);margin:0 1px}.components-color-palette__custom-color-value{color:#757575}.components-color-palette__custom-color-value--is-hex{text-transform:uppercase}.components-color-palette__custom-color-value:empty:after{content:"";visibility:hidden}.components-custom-gradient-picker__gradient-bar{border-radius:2px;height:48px;position:relative;width:100%;z-index:1}.components-custom-gradient-picker__gradient-bar.has-gradient{background-image:repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0),repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0);background-position:0 0,12px 12px;background-size:24px 24px}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__gradient-bar-background{inset:0;position:absolute}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__markers-container{margin-left:auto;margin-right:auto;position:relative;width:calc(100% - 48px)}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-dropdown{display:flex;height:16px;position:absolute;top:16px;width:16px}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown{background:#fff;border-radius:50%;color:#1e1e1e;height:inherit;min-width:16px!important;padding:2px;position:relative;width:inherit}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown svg{height:100%;width:100%}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button{border-radius:50%;box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 2px 0 #00000040;height:inherit;outline:2px solid #0000;padding:0;width:inherit}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button.is-active,.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button:focus{box-shadow:inset 0 0 0 calc(var(--wp-admin-border-width-focus)*2) #fff,0 0 2px 0 #00000040;outline:1.5px solid #0000}.components-custom-gradient-picker__remove-control-point-wrapper{padding-bottom:8px}.components-custom-gradient-picker__inserter{direction:ltr}.components-custom-gradient-picker__liner-gradient-indicator{display:inline-block;flex:0 auto;height:20px;width:20px}.components-custom-gradient-picker__ui-line{position:relative;z-index:0}.block-editor-dimension-control .components-base-control__field{align-items:center;display:flex}.block-editor-dimension-control .components-base-control__label{align-items:center;display:flex;margin-bottom:0;margin-right:1em}.block-editor-dimension-control .components-base-control__label .dashicon{margin-right:.5em}.block-editor-dimension-control.is-manual .components-base-control__label{width:10em}body.is-dragging-components-draggable{cursor:move;cursor:grabbing!important}.components-draggable__invisible-drag-image{height:50px;left:-1000px;position:fixed;width:50px}.components-draggable__clone{background:#0000;padding:0;pointer-events:none;position:fixed;z-index:1000000000}.components-drop-zone{border-radius:2px;bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;visibility:hidden;z-index:40}.components-drop-zone.is-active{opacity:1;visibility:visible}.components-drop-zone .components-drop-zone__content{align-items:center;background-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));bottom:0;color:#fff;display:flex;height:100%;justify-content:center;left:0;opacity:0;pointer-events:none;position:absolute;right:0;text-align:center;top:0;width:100%;z-index:50}.components-drop-zone .components-drop-zone__content-inner{opacity:0;transform:scale(.9)}.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{opacity:1}@media not (prefers-reduced-motion){.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{transition:opacity .2s ease-in-out}}.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{opacity:1;transform:scale(1)}@media not (prefers-reduced-motion){.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{transition:opacity .1s ease-in-out .1s,transform .1s ease-in-out .1s}}.components-drop-zone__content-icon,.components-drop-zone__content-text{display:block}.components-drop-zone__content-icon{line-height:0;margin:0 auto 8px;fill:currentColor;pointer-events:none}.components-drop-zone__content-text{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.components-dropdown{display:inline-block}.components-dropdown__content .components-popover__content{padding:8px}.components-dropdown__content .components-popover__content:has(.components-menu-group){padding:0}.components-dropdown__content .components-popover__content:has(.components-menu-group) .components-dropdown-menu__menu>.components-menu-item__button,.components-dropdown__content .components-popover__content:has(.components-menu-group)>.components-menu-item__button{margin:8px;width:auto}.components-dropdown__content [role=menuitem]{white-space:nowrap}.components-dropdown__content .components-menu-group{padding:8px}.components-dropdown__content .components-menu-group+.components-menu-group{border-top:1px solid #ccc;padding:8px}.components-dropdown__content.is-alternate .components-menu-group+.components-menu-group{border-color:#1e1e1e}.components-dropdown-menu__toggle{vertical-align:top}.components-dropdown-menu__menu{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.4;width:100%}.components-dropdown-menu__menu .components-dropdown-menu__menu-item,.components-dropdown-menu__menu .components-menu-item{cursor:pointer;outline:none;padding:6px;white-space:nowrap;width:100%}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator,.components-dropdown-menu__menu .components-menu-item.has-separator{margin-top:6px;overflow:visible;position:relative}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator:before,.components-dropdown-menu__menu .components-menu-item.has-separator:before{background-color:#ddd;box-sizing:initial;content:"";display:block;height:1px;left:0;position:absolute;right:0;top:-3px}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active svg,.components-dropdown-menu__menu .components-menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-menu-item.is-active svg{background:#1e1e1e;border-radius:1px;box-shadow:0 0 0 1px #1e1e1e;color:#fff}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-icon-only,.components-dropdown-menu__menu .components-menu-item.is-icon-only{width:auto}.components-dropdown-menu__menu .components-menu-item__button,.components-dropdown-menu__menu .components-menu-item__button.components-button{height:auto;min-height:40px;padding-left:8px;padding-right:8px;text-align:left}.components-duotone-picker__color-indicator:before{background:#0000}.components-duotone-picker__color-indicator>.components-button,.components-duotone-picker__color-indicator>.components-button.is-pressed:hover:not(:disabled){background:linear-gradient(-45deg,#0000 48%,#ddd 0,#ddd 52%,#0000 0);color:#0000}.components-duotone-picker__color-indicator>.components-button:not([aria-disabled=true]):active{color:#0000}.components-color-list-picker,.components-color-list-picker__swatch-button{width:100%}.components-color-list-picker__color-picker{margin:8px 0}.components-color-list-picker__swatch-color{margin:2px}.components-external-link{text-decoration:none}.components-external-link__contents{text-decoration:underline}.components-external-link__icon{font-weight:400;margin-left:.5ch}.components-form-toggle{display:inline-block;height:16px;position:relative}.components-form-toggle .components-form-toggle__track{background-color:#fff;border:1px solid #949494;border-radius:8px;box-sizing:border-box;content:"";display:inline-block;height:16px;overflow:hidden;position:relative;vertical-align:top;width:32px}@media not (prefers-reduced-motion){.components-form-toggle .components-form-toggle__track{transition:background-color .2s ease,border-color .2s ease}}.components-form-toggle .components-form-toggle__track:after{border-top:16px solid #0000;box-sizing:border-box;content:"";inset:0;opacity:0;position:absolute}@media not (prefers-reduced-motion){.components-form-toggle .components-form-toggle__track:after{transition:opacity .2s ease}}.components-form-toggle .components-form-toggle__thumb{background-color:#1e1e1e;border:6px solid #0000;border-radius:50%;box-shadow:0 1px 1px #00000008,0 1px 2px #00000005,0 3px 3px #00000005,0 4px 4px #00000003;box-sizing:border-box;display:block;height:12px;left:2px;position:absolute;top:2px;width:12px}@media not (prefers-reduced-motion){.components-form-toggle .components-form-toggle__thumb{transition:transform .2s ease,background-color .2s ease-out}}.components-form-toggle.is-checked .components-form-toggle__track{background-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-form-toggle.is-checked .components-form-toggle__track:after{opacity:1}.components-form-toggle .components-form-toggle__input:focus+.components-form-toggle__track{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000;outline-offset:2px}.components-form-toggle.is-checked .components-form-toggle__thumb{background-color:#fff;border-width:0;transform:translateX(16px)}.components-disabled .components-form-toggle,.components-form-toggle.is-disabled{opacity:.3}.components-form-toggle input.components-form-toggle__input[type=checkbox]{border:none;height:100%;left:0;margin:0;opacity:0;padding:0;position:absolute;top:0;width:100%;z-index:1}.components-form-toggle input.components-form-toggle__input[type=checkbox]:checked{background:none}.components-form-toggle input.components-form-toggle__input[type=checkbox]:before{content:""}.components-form-toggle input.components-form-toggle__input[type=checkbox]:not(:disabled,[aria-disabled=true]){cursor:pointer}.components-form-token-field__input-container{border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;cursor:text;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;line-height:normal;padding:0;width:100%}@media not (prefers-reduced-motion){.components-form-token-field__input-container{transition:box-shadow .1s linear}}@media (min-width:600px){.components-form-token-field__input-container{font-size:13px;line-height:normal}}.components-form-token-field__input-container:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-form-token-field__input-container::-webkit-input-placeholder{color:#1e1e1e9e}.components-form-token-field__input-container::-moz-placeholder{color:#1e1e1e9e}.components-form-token-field__input-container:-ms-input-placeholder{color:#1e1e1e9e}.components-form-token-field__input-container.is-disabled{background:#ddd;border-color:#ddd}.components-form-token-field__input-container.is-active{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-form-token-field__input-container input[type=text].components-form-token-field__input{background:inherit;border:0;box-shadow:none;color:#1e1e1e;display:inline-block;flex:1;font-family:inherit;font-size:16px;margin-left:4px;max-width:100%;min-height:24px;min-width:50px;padding:0;width:100%}@media (min-width:600px){.components-form-token-field__input-container input[type=text].components-form-token-field__input{font-size:13px}}.components-form-token-field.is-active .components-form-token-field__input-container input[type=text].components-form-token-field__input,.components-form-token-field__input-container input[type=text].components-form-token-field__input:focus{box-shadow:none;outline:none}.components-form-token-field__input-container .components-form-token-field__token+input[type=text].components-form-token-field__input{width:auto}.components-form-token-field__token{color:#1e1e1e;display:flex;font-size:13px;max-width:100%}.components-form-token-field__token.is-success .components-form-token-field__remove-token,.components-form-token-field__token.is-success .components-form-token-field__token-text{background:#4ab866}.components-form-token-field__token.is-error .components-form-token-field__remove-token,.components-form-token-field__token.is-error .components-form-token-field__token-text{background:#cc1818}.components-form-token-field__token.is-validating .components-form-token-field__remove-token,.components-form-token-field__token.is-validating .components-form-token-field__token-text{color:#757575}.components-form-token-field__token.is-borderless{padding:0 24px 0 0;position:relative}.components-form-token-field__token.is-borderless .components-form-token-field__token-text{background:#0000}.components-form-token-field__token.is-borderless:not(.is-disabled) .components-form-token-field__token-text{color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-form-token-field__token.is-borderless .components-form-token-field__remove-token{background:#0000;color:#757575;position:absolute;right:0;top:1px}.components-form-token-field__token.is-borderless.is-success .components-form-token-field__token-text{color:#4ab866}.components-form-token-field__token.is-borderless.is-error .components-form-token-field__token-text{color:#cc1818;padding:0 4px 0 6px}.components-form-token-field__token.is-borderless.is-validating .components-form-token-field__token-text{color:#1e1e1e}.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{background:#ddd;display:inline-block;height:auto;min-width:unset}@media not (prefers-reduced-motion){.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{transition:all .2s cubic-bezier(.4,1,.4,1)}}.components-form-token-field__token-text{border-radius:1px 0 0 1px;line-height:24px;overflow:hidden;padding:0 0 0 8px;text-overflow:ellipsis;white-space:nowrap}.components-form-token-field__remove-token.components-button{border-radius:0 1px 1px 0;color:#1e1e1e;line-height:10px;overflow:initial}.components-form-token-field__remove-token.components-button:hover:not(:disabled){color:#1e1e1e}.components-form-token-field__suggestions-list{box-shadow:inset 0 1px 0 0 #949494;flex:1 0 100%;list-style:none;margin:0;max-height:128px;min-width:100%;overflow-y:auto;padding:0}@media not (prefers-reduced-motion){.components-form-token-field__suggestions-list{transition:all .15s ease-in-out}}.components-form-token-field__suggestion{box-sizing:border-box;color:#1e1e1e;display:block;font-size:13px;margin:0;min-height:32px;padding:8px 12px}.components-form-token-field__suggestion.is-selected{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:#fff}.components-form-token-field__suggestion[aria-disabled=true]{color:#949494;pointer-events:none}.components-form-token-field__suggestion[aria-disabled=true].is-selected{background-color:rgba(var(--wp-components-color-accent--rgb,var(--wp-admin-theme-color--rgb)),.04)}.components-form-token-field__suggestion:not(.is-empty){cursor:pointer}@media (min-width:600px){.components-guide{width:600px}}.components-guide .components-modal__content{margin-top:0;padding:0}.components-guide .components-modal__content:before{content:none}.components-guide .components-modal__header{border-bottom:none;height:60px;padding:0;position:sticky}.components-guide .components-modal__header .components-button{align-self:flex-start;margin:8px 8px 0 0;position:static}.components-guide .components-modal__header .components-button:hover svg{fill:#fff}.components-guide .components-guide__container{display:flex;flex-direction:column;justify-content:space-between;margin-top:-60px;min-height:100%}.components-guide .components-guide__page{display:flex;flex-direction:column;justify-content:center;position:relative}@media (min-width:600px){.components-guide .components-guide__page{min-height:300px}}.components-guide .components-guide__footer{align-content:center;display:flex;height:36px;justify-content:center;margin:0 0 24px;padding:0 32px;position:relative;width:100%}.components-guide .components-guide__page-control{margin:0;text-align:center}.components-guide .components-guide__page-control li{display:inline-block;margin:0}.components-guide .components-guide__page-control .components-button{color:#e0e0e0;margin:-6px 0}.components-guide .components-guide__page-control li[aria-current=step] .components-button{color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-modal__frame.components-guide{border:none;max-height:575px;min-width:312px}@media (max-width:600px){.components-modal__frame.components-guide{margin:auto;max-width:calc(100vw - 32px)}}.components-button.components-guide__back-button,.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{position:absolute}.components-button.components-guide__back-button{left:32px}.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{right:32px}[role=region]{position:relative}.is-focusing-regions [role=region]:focus:after,[role=region].interface-interface-skeleton__content:focus-visible:after{bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:1000000}.is-focusing-regions .editor-post-publish-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-entities-saved-states-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-publish-panel,.is-focusing-regions .interface-interface-skeleton__sidebar .editor-layout__toggle-sidebar-panel,.is-focusing-regions [role=region]:focus:after,.is-focusing-regions.is-distraction-free .interface-interface-skeleton__header .edit-post-header,[role=region].interface-interface-skeleton__content:focus-visible:after{outline-color:var(--wp-admin-theme-color);outline-offset:calc(((-1*var(--wp-admin-border-width-focus))/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2);outline-style:solid;outline-width:calc((var(--wp-admin-border-width-focus)/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2)}.components-menu-group+.components-menu-group{border-top:1px solid #1e1e1e;padding-top:8px}.components-menu-group+.components-menu-group.has-hidden-separator{border-top:none;margin-top:0;padding-top:0}.components-menu-group:has(>div:empty){display:none}.components-menu-group__label{color:#757575;font-size:11px;font-weight:500;margin-bottom:12px;margin-top:4px;padding:0 8px;text-transform:uppercase;white-space:nowrap}.components-menu-item__button,.components-menu-item__button.components-button{width:100%}.components-menu-item__button.components-button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button.components-button[role=menuitemradio] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemradio] .components-menu-item__item:only-child{box-sizing:initial;padding-right:48px}.components-menu-item__button .components-menu-items__item-icon,.components-menu-item__button.components-button .components-menu-items__item-icon{display:inline-block;flex:0 0 auto}.components-menu-item__button .components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-items__item-icon.has-icon-right{margin-left:24px;margin-right:-2px}.components-menu-item__button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right{margin-left:8px}.components-menu-item__button .block-editor-block-icon,.components-menu-item__button.components-button .block-editor-block-icon{margin-left:-2px;margin-right:8px}.components-menu-item__button.components-button.is-primary,.components-menu-item__button.is-primary{justify-content:center}.components-menu-item__button.components-button.is-primary .components-menu-item__item,.components-menu-item__button.is-primary .components-menu-item__item{margin-right:0}.components-menu-item__button.components-button:disabled.is-tertiary,.components-menu-item__button.components-button[aria-disabled=true].is-tertiary,.components-menu-item__button:disabled.is-tertiary,.components-menu-item__button[aria-disabled=true].is-tertiary{background:none;color:var(--wp-components-color-accent-darker-10,var(--wp-admin-theme-color-darker-10,#2145e6));opacity:.3}.components-menu-item__info-wrapper{display:flex;flex-direction:column;margin-right:auto}.components-menu-item__info{color:#757575;font-size:12px;margin-top:4px;white-space:normal}.components-menu-item__item{align-items:center;display:inline-flex;margin-right:auto;min-width:160px;white-space:nowrap}.components-menu-item__shortcut{align-self:center;color:currentColor;display:none;margin-left:auto;margin-right:0;padding-left:24px}@media (min-width:480px){.components-menu-item__shortcut{display:inline}}.components-menu-items-choice,.components-menu-items-choice.components-button{height:auto;min-height:40px}.components-menu-items-choice svg,.components-menu-items-choice.components-button svg{margin-right:12px}.components-menu-items-choice.components-button.has-icon,.components-menu-items-choice.has-icon{padding-left:12px}.components-modal__screen-overlay{background-color:#00000059;bottom:0;display:flex;left:0;position:fixed;right:0;top:0;z-index:100000}@keyframes __wp-base-styles-fade-in{0%{opacity:0}to{opacity:1}}@media not (prefers-reduced-motion){.components-modal__screen-overlay{animation:__wp-base-styles-fade-in .08s linear 0s;animation-fill-mode:forwards}}@keyframes __wp-base-styles-fade-out{0%{opacity:1}to{opacity:0}}@media not (prefers-reduced-motion){.components-modal__screen-overlay.is-animating-out{animation:__wp-base-styles-fade-out .08s linear 80ms;animation-fill-mode:forwards}}.components-modal__frame{animation-fill-mode:forwards;animation-name:components-modal__appear-animation;animation-timing-function:cubic-bezier(.29,0,0,1);background:#fff;border-radius:8px 8px 0 0;box-shadow:0 5px 15px #00000014,0 15px 27px #00000012,0 30px 36px #0000000a,0 50px 43px #00000005;box-sizing:border-box;display:flex;margin:40px 0 0;overflow:hidden;width:100%}.components-modal__frame *,.components-modal__frame :after,.components-modal__frame :before{box-sizing:inherit}@media not (prefers-reduced-motion){.components-modal__frame{animation-duration:var(--modal-frame-animation-duration)}}.components-modal__screen-overlay.is-animating-out .components-modal__frame{animation-name:components-modal__disappear-animation;animation-timing-function:cubic-bezier(1,0,.2,1)}@media (min-width:600px){.components-modal__frame{border-radius:8px;margin:auto;max-height:calc(100% - 120px);max-width:calc(100% - 32px);min-width:350px;width:auto}}@media (min-width:600px) and (min-width:600px){.components-modal__frame.is-full-screen{height:calc(100% - 32px);max-height:none;width:calc(100% - 32px)}}@media (min-width:600px) and (min-width:782px){.components-modal__frame.is-full-screen{height:calc(100% - 80px);max-width:none;width:calc(100% - 80px)}}@media (min-width:600px){.components-modal__frame.has-size-large,.components-modal__frame.has-size-medium,.components-modal__frame.has-size-small{width:100%}.components-modal__frame.has-size-small{max-width:384px}.components-modal__frame.has-size-medium{max-width:512px}.components-modal__frame.has-size-large{max-width:840px}}@media (min-width:960px){.components-modal__frame{max-height:70%}}@keyframes components-modal__appear-animation{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}@keyframes components-modal__disappear-animation{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.9)}}.components-modal__header{align-items:center;border-bottom:1px solid #0000;box-sizing:border-box;display:flex;flex-direction:row;height:72px;justify-content:space-between;left:0;padding:24px 32px 8px;position:absolute;top:0;width:100%;z-index:10}.components-modal__header .components-modal__header-heading{font-size:1.2rem;font-weight:600}.components-modal__header h1{line-height:1;margin:0}.components-modal__content.has-scrolled-content:not(.hide-header) .components-modal__header{border-bottom-color:#ddd}.components-modal__header+p{margin-top:0}.components-modal__header-heading-container{align-items:center;display:flex;flex-direction:row;flex-grow:1;justify-content:left}.components-modal__header-icon-container{display:inline-block}.components-modal__header-icon-container svg{max-height:36px;max-width:36px;padding:8px}.components-modal__content{flex:1;margin-top:72px;overflow:auto;padding:4px 32px 32px}.components-modal__content.hide-header{margin-top:0;padding-top:32px}.components-modal__content.is-scrollable:focus-visible{box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000;outline-offset:-2px}.components-notice{align-items:center;background-color:#fff;border-left:4px solid var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:#1e1e1e;display:flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;padding:8px 12px}.components-notice.is-dismissible{position:relative}.components-notice.is-success{background-color:#eff9f1;border-left-color:#4ab866}.components-notice.is-warning{background-color:#fef8ee;border-left-color:#f0b849}.components-notice.is-error{background-color:#f4a2a2;border-left-color:#cc1818}.components-notice__content{flex-grow:1;margin:4px 25px 4px 0}.components-notice__actions{display:flex;flex-wrap:wrap}.components-notice__action.components-button{margin-right:8px}.components-notice__action.components-button,.components-notice__action.components-button.is-link{margin-left:12px}.components-notice__action.components-button.is-secondary{vertical-align:initial}.components-notice__dismiss{align-self:flex-start;color:#757575;flex-shrink:0}.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):focus,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):active,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{background-color:initial;color:#1e1e1e}.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{box-shadow:none}.components-notice-list{box-sizing:border-box;max-width:100vw}.components-notice-list .components-notice__content{line-height:2;margin-bottom:12px;margin-top:12px}.components-notice-list .components-notice__action.components-button{display:block;margin-left:0;margin-top:8px}.components-panel{background:#fff;border:1px solid #e0e0e0}.components-panel>.components-panel__body:first-child,.components-panel>.components-panel__header:first-child{margin-top:-1px}.components-panel>.components-panel__body:last-child,.components-panel>.components-panel__header:last-child{border-bottom-width:0}.components-panel+.components-panel{margin-top:-1px}.components-panel__body{border-bottom:1px solid #e0e0e0;border-top:1px solid #e0e0e0}.components-panel__body h3{margin:0 0 .5em}.components-panel__body.is-opened{padding:16px}.components-panel__header{align-items:center;border-bottom:1px solid #ddd;box-sizing:initial;display:flex;flex-shrink:0;height:47px;justify-content:space-between;padding:0 16px}.components-panel__header h2{color:inherit;font-size:inherit;margin:0}.components-panel__body+.components-panel__body,.components-panel__body+.components-panel__header,.components-panel__header+.components-panel__body,.components-panel__header+.components-panel__header{margin-top:-1px}.components-panel__body>.components-panel__body-title{display:block;font-size:inherit;margin-bottom:0;margin-top:0;padding:0}@media not (prefers-reduced-motion){.components-panel__body>.components-panel__body-title{transition:background .1s ease-in-out}}.components-panel__body.is-opened>.components-panel__body-title{margin:-16px -16px 5px}.components-panel__body>.components-panel__body-title:hover{background:#f0f0f0;border:none}.components-panel__body-toggle.components-button{border:none;box-shadow:none;color:#1e1e1e;font-weight:500;height:auto;outline:none;padding:16px 48px 16px 16px;position:relative;text-align:left;width:100%}@media not (prefers-reduced-motion){.components-panel__body-toggle.components-button{transition:background .1s ease-in-out}}.components-panel__body-toggle.components-button:focus{border-radius:0;box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-panel__body-toggle.components-button .components-panel__arrow{color:#1e1e1e;position:absolute;right:16px;top:50%;transform:translateY(-50%);fill:currentColor}@media not (prefers-reduced-motion){.components-panel__body-toggle.components-button .components-panel__arrow{transition:color .1s ease-in-out}}body.rtl .components-panel__body-toggle.components-button .dashicons-arrow-right{-ms-filter:fliph;filter:FlipH;margin-top:-10px;transform:scaleX(-1)}.components-panel__icon{color:#757575;margin:-2px 0 -2px 6px}.components-panel__body-toggle-icon{margin-right:-5px}.components-panel__color-title{float:left;height:19px}.components-panel__row{align-items:center;display:flex;justify-content:space-between;margin-top:8px;min-height:36px}.components-panel__row select{min-width:0}.components-panel__row label{flex-shrink:0;margin-right:12px;max-width:75%}.components-panel__row:empty,.components-panel__row:first-of-type{margin-top:0}.components-panel .circle-picker{padding-bottom:20px}.components-placeholder.components-placeholder{align-items:flex-start;box-sizing:border-box;color:#1e1e1e;display:flex;flex-direction:column;font-size:13px;gap:16px;margin:0;padding:24px;position:relative;text-align:left;width:100%;-moz-font-smoothing:subpixel-antialiased;-webkit-font-smoothing:subpixel-antialiased;background-color:#fff;border-radius:2px;box-shadow:inset 0 0 0 1px #1e1e1e;outline:1px solid #0000}.components-placeholder__error,.components-placeholder__fieldset,.components-placeholder__instructions,.components-placeholder__label{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;font-weight:400;letter-spacing:normal;line-height:normal;text-transform:none}.components-placeholder__label{align-items:center;display:flex;font-weight:600}.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{margin-right:4px;fill:currentColor}@media (forced-colors:active){.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{fill:CanvasText}}.components-placeholder__label:empty{display:none}.components-placeholder__fieldset,.components-placeholder__fieldset form{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px;justify-content:flex-start;width:100%}.components-placeholder__fieldset form p,.components-placeholder__fieldset p{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.components-placeholder__fieldset.is-column-layout,.components-placeholder__fieldset.is-column-layout form{flex-direction:column}.components-placeholder__input[type=url]{border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;flex:1 1 auto;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;line-height:normal;padding:6px 8px}@media not (prefers-reduced-motion){.components-placeholder__input[type=url]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-placeholder__input[type=url]{font-size:13px;line-height:normal}}.components-placeholder__input[type=url]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-placeholder__input[type=url]::-webkit-input-placeholder{color:#1e1e1e9e}.components-placeholder__input[type=url]::-moz-placeholder{color:#1e1e1e9e}.components-placeholder__input[type=url]:-ms-input-placeholder{color:#1e1e1e9e}.components-placeholder__error{gap:8px;width:100%}.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link{margin-left:10px;margin-right:10px}.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link:last-child{margin-right:0}.components-placeholder.is-medium .components-placeholder__instructions,.components-placeholder.is-small .components-placeholder__instructions{display:none}.components-placeholder.is-medium .components-placeholder__fieldset,.components-placeholder.is-medium .components-placeholder__fieldset form,.components-placeholder.is-small .components-placeholder__fieldset,.components-placeholder.is-small .components-placeholder__fieldset form{flex-direction:column}.components-placeholder.is-medium .components-button,.components-placeholder.is-medium .components-placeholder__fieldset>*,.components-placeholder.is-small .components-button,.components-placeholder.is-small .components-placeholder__fieldset>*{justify-content:center;width:100%}.components-placeholder.is-small{padding:16px}.components-placeholder.has-illustration{-webkit-backdrop-filter:blur(100px);backdrop-filter:blur(100px);backface-visibility:hidden;background-color:initial;border-radius:0;box-shadow:none;color:inherit;display:flex;overflow:hidden}.is-dark-theme .components-placeholder.has-illustration{background-color:#0000001a}.components-placeholder.has-illustration .components-placeholder__fieldset{margin-left:0;margin-right:0}.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{opacity:0;pointer-events:none}@media not (prefers-reduced-motion){.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{transition:opacity .1s linear}}.is-selected>.components-placeholder.has-illustration .components-button,.is-selected>.components-placeholder.has-illustration .components-placeholder__instructions,.is-selected>.components-placeholder.has-illustration .components-placeholder__label{opacity:1;pointer-events:auto}.components-placeholder.has-illustration:before{background:currentColor;bottom:0;content:"";left:0;opacity:.1;pointer-events:none;position:absolute;right:0;top:0}.is-selected .components-placeholder.has-illustration{overflow:auto}.components-placeholder__preview{display:flex;justify-content:center}.components-placeholder__illustration{box-sizing:initial;height:100%;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:100%;stroke:currentColor;opacity:.25}.components-popover{box-sizing:border-box;will-change:transform;z-index:1000000}.components-popover *,.components-popover :after,.components-popover :before{box-sizing:inherit}.components-popover.is-expanded{bottom:0;left:0;position:fixed;right:0;top:0;z-index:1000000!important}.components-popover__content{background:#fff;border-radius:4px;box-shadow:0 0 0 1px #ccc,0 2px 3px #0000000d,0 4px 5px #0000000a,0 12px 12px #00000008,0 16px 16px #00000005;box-sizing:border-box;width:min-content}.is-alternate .components-popover__content{border-radius:2px;box-shadow:0 0 0 1px #1e1e1e}.is-unstyled .components-popover__content{background:none;border-radius:0;box-shadow:none}.components-popover.is-expanded .components-popover__content{box-shadow:0 -1px 0 0 #ccc;height:calc(100% - 48px);overflow-y:visible;position:static;width:auto}.components-popover.is-expanded.is-alternate .components-popover__content{box-shadow:0 -1px 0 #1e1e1e}.components-popover__header{align-items:center;background:#fff;display:flex;height:48px;justify-content:space-between;padding:0 8px 0 16px}.components-popover__header-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.components-popover__close.components-button{z-index:5}.components-popover__arrow{display:flex;height:14px;pointer-events:none;position:absolute;width:14px}.components-popover__arrow:before{background-color:#fff;content:"";height:2px;left:1px;position:absolute;right:1px;top:-1px}.components-popover__arrow.is-top{bottom:-14px!important;transform:rotate(0)}.components-popover__arrow.is-right{left:-14px!important;transform:rotate(90deg)}.components-popover__arrow.is-bottom{top:-14px!important;transform:rotate(180deg)}.components-popover__arrow.is-left{right:-14px!important;transform:rotate(-90deg)}.components-popover__triangle{display:block;flex:1}.components-popover__triangle-bg{fill:#fff}.components-popover__triangle-border{fill:#0000;stroke-width:1px;stroke:#ccc}.is-alternate .components-popover__triangle-border{stroke:#1e1e1e}.components-radio-control{border:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;margin:0;padding:0}.components-radio-control__group-wrapper.has-help{margin-block-end:12px}.components-radio-control__option{align-items:center;column-gap:8px;display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto minmax(0,max-content)}.components-radio-control__input[type=radio]{appearance:none;border:1px solid #1e1e1e;border-radius:2px;border-radius:50%;box-shadow:0 0 0 #0000;cursor:pointer;display:inline-flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;grid-column:1;grid-row:1;height:24px;line-height:normal;margin:0;max-width:24px;min-width:24px;padding:0;position:relative;transition:none;width:24px}@media not (prefers-reduced-motion){.components-radio-control__input[type=radio]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-radio-control__input[type=radio]{font-size:13px;line-height:normal}}.components-radio-control__input[type=radio]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color)}.components-radio-control__input[type=radio]::-webkit-input-placeholder{color:#1e1e1e9e}.components-radio-control__input[type=radio]::-moz-placeholder{color:#1e1e1e9e}.components-radio-control__input[type=radio]:-ms-input-placeholder{color:#1e1e1e9e}@media (min-width:600px){.components-radio-control__input[type=radio]{height:16px;max-width:16px;min-width:16px;width:16px}}.components-radio-control__input[type=radio]:checked:before{background-color:#fff;border:4px solid #fff;box-sizing:inherit;height:12px;left:50%;margin:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:12px}@media (min-width:600px){.components-radio-control__input[type=radio]:checked:before{height:8px;width:8px}}.components-radio-control__input[type=radio]:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--wp-admin-theme-color)}.components-radio-control__input[type=radio]:checked{background:var(--wp-admin-theme-color);border:none}.components-radio-control__input[type=radio]:focus{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);outline:2px solid #0000;outline-offset:2px}.components-radio-control__input[type=radio]:checked{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-radio-control__input[type=radio]:checked:before{border-radius:50%;content:""}.components-radio-control__label{cursor:pointer;grid-column:2;grid-row:1;line-height:24px}@media (min-width:600px){.components-radio-control__label{line-height:16px}}.components-radio-control__option-description{grid-column:2;grid-row:2;padding-block-start:4px}.components-radio-control__option-description.components-radio-control__option-description{margin-top:0}.components-resizable-box__handle{display:none;height:23px;width:23px;z-index:2}.components-resizable-box__container.has-show-handle .components-resizable-box__handle{display:block}.components-resizable-box__handle>div{height:100%;outline:none;position:relative;width:100%;z-index:2}.components-resizable-box__container>img{width:inherit}.components-resizable-box__handle:after{background:#fff;border-radius:50%;box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),0 1px 1px #00000008,0 1px 2px #00000005,0 3px 3px #00000005,0 4px 4px #00000003;content:"";cursor:inherit;display:block;height:15px;outline:2px solid #0000;position:absolute;right:calc(50% - 8px);top:calc(50% - 8px);width:15px}.components-resizable-box__side-handle:before{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-radius:9999px;content:"";cursor:inherit;display:block;height:3px;opacity:0;position:absolute;right:calc(50% - 1px);top:calc(50% - 1px);width:3px}@media not (prefers-reduced-motion){.components-resizable-box__side-handle:before{transition:transform .1s ease-in;will-change:transform}}.components-resizable-box__corner-handle,.components-resizable-box__side-handle{z-index:2}.components-resizable-box__side-handle.components-resizable-box__handle-bottom,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:before,.components-resizable-box__side-handle.components-resizable-box__handle-top,.components-resizable-box__side-handle.components-resizable-box__handle-top:before{border-left:0;border-right:0;left:0;width:100%}.components-resizable-box__side-handle.components-resizable-box__handle-left,.components-resizable-box__side-handle.components-resizable-box__handle-left:before,.components-resizable-box__side-handle.components-resizable-box__handle-right,.components-resizable-box__side-handle.components-resizable-box__handle-right:before{border-bottom:0;border-top:0;height:100%;top:0}@media not (prefers-reduced-motion){.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{animation:components-resizable-box__top-bottom-animation .1s ease-out 0s;animation-fill-mode:forwards}.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before{animation:components-resizable-box__left-right-animation .1s ease-out 0s;animation-fill-mode:forwards}}@media not all and (min-resolution:0.001dpcm){@supports (-webkit-appearance:none){.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{animation:none}}}@keyframes components-resizable-box__top-bottom-animation{0%{opacity:0;transform:scaleX(0)}to{opacity:1;transform:scaleX(1)}}@keyframes components-resizable-box__left-right-animation{0%{opacity:0;transform:scaleY(0)}to{opacity:1;transform:scaleY(1)}}
/*!rtl:begin:ignore*/.components-resizable-box__handle-right{right:-11.5px}.components-resizable-box__handle-left{left:-11.5px}.components-resizable-box__handle-top{top:-11.5px}.components-resizable-box__handle-bottom{bottom:-11.5px}
/*!rtl:end:ignore*/.components-responsive-wrapper{align-items:center;display:flex;justify-content:center;max-width:100%;position:relative}.components-responsive-wrapper__content{display:block;max-width:100%;width:100%}.components-sandbox{overflow:hidden}iframe.components-sandbox{width:100%}body.lockscroll,html.lockscroll{overflow:hidden}.components-select-control__input{outline:0;-webkit-tap-highlight-color:rgba(0,0,0,0)!important}@media (max-width:782px){.components-base-control .components-base-control__field .components-select-control__input{font-size:16px}}.components-snackbar{-webkit-backdrop-filter:blur(16px) saturate(180%);backdrop-filter:blur(16px) saturate(180%);background:#000000d9;border-radius:4px;box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;box-sizing:border-box;color:#fff;cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;max-width:600px;padding:12px 20px;pointer-events:auto;width:100%}@media (min-width:600px){.components-snackbar{width:fit-content}}.components-snackbar:focus{box-shadow:inset 0 0 0 1px #fff,0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-snackbar.components-snackbar-explicit-dismiss{cursor:default}.components-snackbar .components-snackbar__content-with-icon{padding-left:24px;position:relative}.components-snackbar .components-snackbar__icon{left:-8px;position:absolute;top:-2.9px}.components-snackbar .components-snackbar__dismiss-button{cursor:pointer;margin-left:24px}.components-snackbar__action.components-button{color:#fff;flex-shrink:0;margin-left:32px}.components-snackbar__action.components-button:focus{box-shadow:none;outline:1px dotted #fff}.components-snackbar__action.components-button:hover{color:currentColor;text-decoration:none}.components-snackbar__content{align-items:baseline;display:flex;justify-content:space-between;line-height:1.4}.components-snackbar-list{box-sizing:border-box;pointer-events:none;position:absolute;width:100%;z-index:100000}.components-snackbar-list__notice-container{padding-top:8px;position:relative}.components-tab-panel__tabs{align-items:stretch;display:flex;flex-direction:row}.components-tab-panel__tabs[aria-orientation=vertical]{flex-direction:column}.components-tab-panel__tabs-item{background:#0000;border:none;border-radius:0;box-shadow:none;cursor:pointer;font-weight:500;height:48px!important;margin-left:0;padding:3px 16px;position:relative}.components-tab-panel__tabs-item:focus:not(:disabled){box-shadow:none;outline:none;position:relative}.components-tab-panel__tabs-item:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-radius:0;bottom:0;content:"";height:calc(var(--wp-admin-border-width-focus)*0);left:0;pointer-events:none;position:absolute;right:0}@media not (prefers-reduced-motion){.components-tab-panel__tabs-item:after{transition:all .1s linear}}.components-tab-panel__tabs-item.is-active:after{height:calc(var(--wp-admin-border-width-focus)*1);outline:2px solid #0000;outline-offset:-1px}.components-tab-panel__tabs-item:before{border-radius:2px;bottom:12px;box-shadow:0 0 0 0 #0000;content:"";left:12px;pointer-events:none;position:absolute;right:12px;top:12px}@media not (prefers-reduced-motion){.components-tab-panel__tabs-item:before{transition:all .1s linear}}.components-tab-panel__tabs-item:focus-visible:before{box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000}.components-tab-panel__tab-content:focus{box-shadow:none;outline:none}.components-tab-panel__tab-content:focus-visible{box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000;outline-offset:0}.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;height:32px;line-height:normal;margin:0;padding:6px 8px;width:100%}@media not (prefers-reduced-motion){.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{font-size:13px;line-height:normal}}.components-text-control__input:focus,.components-text-control__input[type=color]:focus,.components-text-control__input[type=date]:focus,.components-text-control__input[type=datetime-local]:focus,.components-text-control__input[type=datetime]:focus,.components-text-control__input[type=email]:focus,.components-text-control__input[type=month]:focus,.components-text-control__input[type=number]:focus,.components-text-control__input[type=password]:focus,.components-text-control__input[type=tel]:focus,.components-text-control__input[type=text]:focus,.components-text-control__input[type=time]:focus,.components-text-control__input[type=url]:focus,.components-text-control__input[type=week]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-text-control__input::-webkit-input-placeholder,.components-text-control__input[type=color]::-webkit-input-placeholder,.components-text-control__input[type=date]::-webkit-input-placeholder,.components-text-control__input[type=datetime-local]::-webkit-input-placeholder,.components-text-control__input[type=datetime]::-webkit-input-placeholder,.components-text-control__input[type=email]::-webkit-input-placeholder,.components-text-control__input[type=month]::-webkit-input-placeholder,.components-text-control__input[type=number]::-webkit-input-placeholder,.components-text-control__input[type=password]::-webkit-input-placeholder,.components-text-control__input[type=tel]::-webkit-input-placeholder,.components-text-control__input[type=text]::-webkit-input-placeholder,.components-text-control__input[type=time]::-webkit-input-placeholder,.components-text-control__input[type=url]::-webkit-input-placeholder,.components-text-control__input[type=week]::-webkit-input-placeholder{color:#1e1e1e9e}.components-text-control__input::-moz-placeholder,.components-text-control__input[type=color]::-moz-placeholder,.components-text-control__input[type=date]::-moz-placeholder,.components-text-control__input[type=datetime-local]::-moz-placeholder,.components-text-control__input[type=datetime]::-moz-placeholder,.components-text-control__input[type=email]::-moz-placeholder,.components-text-control__input[type=month]::-moz-placeholder,.components-text-control__input[type=number]::-moz-placeholder,.components-text-control__input[type=password]::-moz-placeholder,.components-text-control__input[type=tel]::-moz-placeholder,.components-text-control__input[type=text]::-moz-placeholder,.components-text-control__input[type=time]::-moz-placeholder,.components-text-control__input[type=url]::-moz-placeholder,.components-text-control__input[type=week]::-moz-placeholder{color:#1e1e1e9e}.components-text-control__input:-ms-input-placeholder,.components-text-control__input[type=color]:-ms-input-placeholder,.components-text-control__input[type=date]:-ms-input-placeholder,.components-text-control__input[type=datetime-local]:-ms-input-placeholder,.components-text-control__input[type=datetime]:-ms-input-placeholder,.components-text-control__input[type=email]:-ms-input-placeholder,.components-text-control__input[type=month]:-ms-input-placeholder,.components-text-control__input[type=number]:-ms-input-placeholder,.components-text-control__input[type=password]:-ms-input-placeholder,.components-text-control__input[type=tel]:-ms-input-placeholder,.components-text-control__input[type=text]:-ms-input-placeholder,.components-text-control__input[type=time]:-ms-input-placeholder,.components-text-control__input[type=url]:-ms-input-placeholder,.components-text-control__input[type=week]:-ms-input-placeholder{color:#1e1e1e9e}.components-text-control__input.is-next-40px-default-size,.components-text-control__input[type=color].is-next-40px-default-size,.components-text-control__input[type=date].is-next-40px-default-size,.components-text-control__input[type=datetime-local].is-next-40px-default-size,.components-text-control__input[type=datetime].is-next-40px-default-size,.components-text-control__input[type=email].is-next-40px-default-size,.components-text-control__input[type=month].is-next-40px-default-size,.components-text-control__input[type=number].is-next-40px-default-size,.components-text-control__input[type=password].is-next-40px-default-size,.components-text-control__input[type=tel].is-next-40px-default-size,.components-text-control__input[type=text].is-next-40px-default-size,.components-text-control__input[type=time].is-next-40px-default-size,.components-text-control__input[type=url].is-next-40px-default-size,.components-text-control__input[type=week].is-next-40px-default-size{height:40px;padding-left:12px;padding-right:12px}.components-text-control__input[type=email],.components-text-control__input[type=url]{direction:ltr}.components-tip{color:#757575;display:flex}.components-tip svg{align-self:center;fill:#f0b849;flex-shrink:0;margin-right:16px}.components-tip p{margin:0}.components-toggle-control__label{line-height:16px}.components-toggle-control__label:not(.is-disabled){cursor:pointer}.components-toggle-control__help{display:inline-block;margin-inline-start:40px}.components-accessible-toolbar{border:1px solid #1e1e1e;border-radius:2px;display:inline-flex;flex-shrink:0}.components-accessible-toolbar>.components-toolbar-group:last-child{border-right:none}.components-accessible-toolbar.is-unstyled{border:none}.components-accessible-toolbar.is-unstyled>.components-toolbar-group{border-right:none}.components-accessible-toolbar[aria-orientation=vertical],.components-toolbar[aria-orientation=vertical]{align-items:center;display:flex;flex-direction:column}.components-accessible-toolbar .components-button,.components-toolbar .components-button{height:48px;padding-left:16px;padding-right:16px;position:relative;z-index:1}.components-accessible-toolbar .components-button:focus:not(:disabled),.components-toolbar .components-button:focus:not(:disabled){box-shadow:none;outline:none}.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{border-radius:2px;content:"";display:block;height:32px;left:8px;position:absolute;right:8px;z-index:-1}@media not (prefers-reduced-motion){.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{animation:components-button__appear-animation .1s ease;animation-fill-mode:forwards}}.components-accessible-toolbar .components-button svg,.components-toolbar .components-button svg{margin-left:auto;margin-right:auto;position:relative}.components-accessible-toolbar .components-button.is-pressed,.components-accessible-toolbar .components-button.is-pressed:hover,.components-toolbar .components-button.is-pressed,.components-toolbar .components-button.is-pressed:hover{background:#0000}.components-accessible-toolbar .components-button.is-pressed:before,.components-toolbar .components-button.is-pressed:before{background:#1e1e1e}.components-accessible-toolbar .components-button:focus:before,.components-toolbar .components-button:focus:before{box-shadow:inset 0 0 0 1px #fff,0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);outline:2px solid #0000}.components-accessible-toolbar .components-button.has-icon.has-icon,.components-toolbar .components-button.has-icon.has-icon{min-width:48px;padding-left:8px;padding-right:8px}@keyframes components-button__appear-animation{0%{transform:scaleY(0)}to{transform:scaleY(1)}}.components-toolbar__control.components-button{position:relative}.components-toolbar__control.components-button[data-subscript] svg{padding:5px 10px 5px 0}.components-toolbar__control.components-button[data-subscript]:after{bottom:10px;content:attr(data-subscript);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;font-weight:600;line-height:12px;position:absolute;right:8px}.components-toolbar__control.components-button:not(:disabled).is-pressed[data-subscript]:after{color:#fff}.components-toolbar-group{background-color:#fff;border-right:1px solid #1e1e1e;display:inline-flex;flex-shrink:0;flex-wrap:wrap;line-height:0;min-height:48px;padding-left:6px;padding-right:6px}.components-toolbar-group .components-toolbar-group.components-toolbar-group{border-width:0;margin:0}.components-toolbar-group .components-button.components-button,.components-toolbar-group .components-button.has-icon.has-icon{justify-content:center;min-width:36px;padding-left:6px;padding-right:6px}.components-toolbar-group .components-button.components-button svg,.components-toolbar-group .components-button.has-icon.has-icon svg{min-width:24px}.components-toolbar-group .components-button.components-button:before,.components-toolbar-group .components-button.has-icon.has-icon:before{left:2px;right:2px}.components-toolbar{background-color:#fff;border:1px solid #1e1e1e;display:inline-flex;flex-shrink:0;flex-wrap:wrap;margin:0;min-height:48px}.components-toolbar .components-toolbar.components-toolbar{border-width:0;margin:0}div.components-toolbar>div{display:flex;margin:0}div.components-toolbar>div+div.has-left-divider{margin-left:6px;overflow:visible;position:relative}div.components-toolbar>div+div.has-left-divider:before{background-color:#ddd;box-sizing:initial;content:"";display:inline-block;height:20px;left:-3px;position:absolute;top:8px;width:1px}.components-tooltip{background:#000;border-radius:2px;box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;color:#f0f0f0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:12px;line-height:1.4;padding:4px 8px;text-align:center;z-index:1000002}.components-tooltip__shortcut{margin-left:8px}@charset "UTF-8";:root{--wp-admin-theme-color:#3858e9;--wp-admin-theme-color--rgb:56,88,233;--wp-admin-theme-color-darker-10:#2145e6;--wp-admin-theme-color-darker-10--rgb:33,69,230;--wp-admin-theme-color-darker-20:#183ad6;--wp-admin-theme-color-darker-20--rgb:24,58,214;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}@media not (prefers-reduced-motion){.components-animate__appear{animation:components-animate__appear-animation .1s cubic-bezier(0,0,.2,1) 0s;animation-fill-mode:forwards}}.components-animate__appear.is-from-top,.components-animate__appear.is-from-top.is-from-left{transform-origin:top right}.components-animate__appear.is-from-top.is-from-right{transform-origin:top left}.components-animate__appear.is-from-bottom,.components-animate__appear.is-from-bottom.is-from-left{transform-origin:bottom right}.components-animate__appear.is-from-bottom.is-from-right{transform-origin:bottom left}@keyframes components-animate__appear-animation{0%{transform:translateY(-2em) scaleY(0) scaleX(0)}to{transform:translateY(0) scaleY(1) scaleX(1)}}@media not (prefers-reduced-motion){.components-animate__slide-in{animation:components-animate__slide-in-animation .1s cubic-bezier(0,0,.2,1);animation-fill-mode:forwards}.components-animate__slide-in.is-from-left{transform:translateX(-100%)}.components-animate__slide-in.is-from-right{transform:translateX(100%)}}@keyframes components-animate__slide-in-animation{to{transform:translateX(0)}}@media not (prefers-reduced-motion){.components-animate__loading{animation:components-animate__loading 1.6s ease-in-out infinite}}@keyframes components-animate__loading{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.components-autocomplete__popover .components-popover__content{min-width:200px;padding:8px}.components-autocomplete__result.components-button{display:flex;height:auto;min-height:36px;text-align:right;width:100%}.components-autocomplete__result.components-button:focus:not(:disabled){box-shadow:inset 0 0 0 1px #fff,0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);outline:2px solid #0000}.components-badge{align-items:center;background-color:color-mix(in srgb,#fff 90%,var(--base-color));border-radius:2px;box-sizing:border-box;color:color-mix(in srgb,#000 50%,var(--base-color));display:inline-flex;font-size:12px;font-weight:400;gap:2px;line-height:20px;max-width:100%;min-height:24px;padding:0 8px}.components-badge *,.components-badge :after,.components-badge :before{box-sizing:inherit}.components-badge:where(.is-default){background-color:#f0f0f0;color:#2f2f2f}.components-badge.has-icon{padding-inline-start:4px}.components-badge.is-info{--base-color:#3858e9}.components-badge.is-warning{--base-color:#f0b849}.components-badge.is-error{--base-color:#cc1818}.components-badge.is-success{--base-color:#4ab866}.components-badge__icon{flex-shrink:0}.components-badge__content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.components-button-group{display:inline-block}.components-button-group .components-button{border-radius:0;box-shadow:inset 0 0 0 1px #1e1e1e;color:#1e1e1e;display:inline-flex}.components-button-group .components-button+.components-button{margin-right:-1px}.components-button-group .components-button:first-child{border-radius:0 2px 2px 0}.components-button-group .components-button:last-child{border-radius:2px 0 0 2px}.components-button-group .components-button.is-primary,.components-button-group .components-button:focus{position:relative;z-index:1}.components-button-group .components-button.is-primary{box-shadow:inset 0 0 0 1px #1e1e1e}.components-button{align-items:center;-webkit-appearance:none;background:none;border:0;border-radius:2px;box-sizing:border-box;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;height:36px;margin:0;padding:6px 12px;text-decoration:none}@media not (prefers-reduced-motion){.components-button{transition:box-shadow .1s linear}}.components-button.is-next-40px-default-size{height:40px}.components-button:hover:not(:disabled,[aria-disabled=true]),.components-button[aria-expanded=true]{color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button:focus:not(:disabled){box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:3px solid #0000}.components-button.is-primary{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:var(--wp-components-color-accent-inverted,#fff);outline:1px solid #0000;text-decoration:none;text-shadow:none;white-space:nowrap}.components-button.is-primary:hover:not(:disabled){background:var(--wp-components-color-accent-darker-10,var(--wp-admin-theme-color-darker-10,#2145e6));color:var(--wp-components-color-accent-inverted,#fff)}.components-button.is-primary:active:not(:disabled){background:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6));border-color:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6));color:var(--wp-components-color-accent-inverted,#fff)}.components-button.is-primary:focus:not(:disabled){box-shadow:inset 0 0 0 1px var(--wp-components-color-background,#fff),0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button.is-primary:disabled,.components-button.is-primary:disabled:active:enabled,.components-button.is-primary[aria-disabled=true],.components-button.is-primary[aria-disabled=true]:active:enabled,.components-button.is-primary[aria-disabled=true]:enabled{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:#fff6;outline:none}.components-button.is-primary:disabled:active:enabled:focus:enabled,.components-button.is-primary:disabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:active:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:enabled:focus:enabled,.components-button.is-primary[aria-disabled=true]:focus:enabled{box-shadow:inset 0 0 0 1px var(--wp-components-color-background,#fff),0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button.is-primary.is-busy,.components-button.is-primary.is-busy:disabled,.components-button.is-primary.is-busy[aria-disabled=true]{background-image:linear-gradient(45deg,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 33%,var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6)) 33%,var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6)) 70%,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 70%);background-size:100px 100%;border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:var(--wp-components-color-accent-inverted,#fff)}.components-button.is-secondary,.components-button.is-tertiary{outline:1px solid #0000}.components-button.is-secondary:active:not(:disabled),.components-button.is-tertiary:active:not(:disabled){box-shadow:none}.components-button.is-secondary:disabled,.components-button.is-secondary[aria-disabled=true],.components-button.is-secondary[aria-disabled=true]:hover,.components-button.is-tertiary:disabled,.components-button.is-tertiary[aria-disabled=true],.components-button.is-tertiary[aria-disabled=true]:hover{background:#0000;color:#949494;transform:none}.components-button.is-secondary{background:#0000;box-shadow:inset 0 0 0 1px var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),0 0 0 currentColor;color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:1px solid #0000;white-space:nowrap}.components-button.is-secondary:hover:not(:disabled,[aria-disabled=true],.is-pressed){background:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 4%,#0000);box-shadow:inset 0 0 0 1px var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6));color:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6))}.components-button.is-secondary:disabled:not(:focus),.components-button.is-secondary[aria-disabled=true]:hover:not(:focus),.components-button.is-secondary[aria-disabled=true]:not(:focus){box-shadow:inset 0 0 0 1px #ddd}.components-button.is-secondary:focus:not(:disabled){box-shadow:0 0 0 currentColor inset,0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-button.is-tertiary{background:#0000;color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));white-space:nowrap}.components-button.is-tertiary:hover:not(:disabled,[aria-disabled=true],.is-pressed){background:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 4%,#0000);color:var(--wp-components-color-accent-darker-20,var(--wp-admin-theme-color-darker-20,#183ad6))}.components-button.is-tertiary:active:not(:disabled,[aria-disabled=true]){background:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)) 8%,#0000)}p+.components-button.is-tertiary{margin-right:-6px}.components-button.is-tertiary:disabled:not(:focus),.components-button.is-tertiary[aria-disabled=true]:hover:not(:focus),.components-button.is-tertiary[aria-disabled=true]:not(:focus){box-shadow:none;outline:none}.components-button.is-destructive{--wp-components-color-accent:#cc1818;--wp-components-color-accent-darker-10:#9e1313;--wp-components-color-accent-darker-20:#710d0d}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link){color:#cc1818}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):hover:not(:disabled,[aria-disabled=true]){color:#710d0d}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):focus{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #cc1818}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):active:not(:disabled,[aria-disabled=true]){background:#ccc}.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link):disabled,.components-button.is-destructive:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link)[aria-disabled=true]{color:#949494}.components-button.is-destructive.is-secondary:hover:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:hover:not(:disabled,[aria-disabled=true]){background:#cc18180a}.components-button.is-destructive.is-secondary:active:not(:disabled,[aria-disabled=true]),.components-button.is-destructive.is-tertiary:active:not(:disabled,[aria-disabled=true]){background:#cc181814}.components-button.is-link{background:none;border:0;border-radius:0;box-shadow:none;color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));height:auto;margin:0;outline:none;padding:0;text-align:right;text-decoration:underline}@media not (prefers-reduced-motion){.components-button.is-link{transition-duration:.05s;transition-property:border,background,color;transition-timing-function:ease-in-out}}.components-button.is-link:focus{border-radius:2px}.components-button.is-link:disabled,.components-button.is-link[aria-disabled=true]{color:#949494}.components-button:not(:disabled,[aria-disabled=true]):active{color:var(--wp-components-color-foreground,#1e1e1e)}.components-button:disabled,.components-button[aria-disabled=true]{color:#949494;cursor:default}.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{background-image:linear-gradient(45deg,#fafafa 33%,#e0e0e0 0,#e0e0e0 70%,#fafafa 0);background-size:100px 100%}@media not (prefers-reduced-motion){.components-button.is-busy,.components-button.is-secondary.is-busy,.components-button.is-secondary.is-busy:disabled,.components-button.is-secondary.is-busy[aria-disabled=true]{animation:components-button__busy-animation 2.5s linear infinite}}.components-button.is-compact{height:32px}.components-button.is-compact.has-icon:not(.has-text){min-width:32px;padding:0;width:32px}.components-button.is-small{font-size:11px;height:24px;line-height:22px;padding:0 8px}.components-button.is-small.has-icon:not(.has-text){min-width:24px;padding:0;width:24px}.components-button.has-icon{justify-content:center;min-width:36px;padding:6px}.components-button.has-icon.is-next-40px-default-size{min-width:40px}.components-button.has-icon .dashicon{align-items:center;box-sizing:initial;display:inline-flex;justify-content:center;padding:2px}.components-button.has-icon.has-text{gap:4px;justify-content:start;padding-left:12px;padding-right:8px}.components-button.is-pressed,.components-button.is-pressed:hover{color:var(--wp-components-color-foreground-inverted,#fff)}.components-button.is-pressed:hover:not(:disabled,[aria-disabled=true]),.components-button.is-pressed:not(:disabled,[aria-disabled=true]){background:var(--wp-components-color-foreground,#1e1e1e)}.components-button.is-pressed:disabled,.components-button.is-pressed[aria-disabled=true]{color:#949494}.components-button.is-pressed:disabled:not(.is-primary):not(.is-secondary):not(.is-tertiary),.components-button.is-pressed[aria-disabled=true]:not(.is-primary):not(.is-secondary):not(.is-tertiary){background:#949494;color:var(--wp-components-color-foreground-inverted,#fff)}.components-button.is-pressed:focus:not(:disabled){box-shadow:inset 0 0 0 1px var(--wp-components-color-background,#fff),0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000}.components-button svg{fill:currentColor;outline:none}@media (forced-colors:active){.components-button svg{fill:CanvasText}}.components-button .components-visually-hidden{height:auto}@keyframes components-button__busy-animation{0%{background-position:right 200px top 0}}.components-checkbox-control{--checkbox-input-size:24px;--checkbox-input-margin:8px}@media (min-width:600px){.components-checkbox-control{--checkbox-input-size:16px}}.components-checkbox-control__label{cursor:pointer;line-height:var(--checkbox-input-size)}.components-checkbox-control__input[type=checkbox]{appearance:none;background:#fff;border:1px solid #1e1e1e;border-radius:2px;box-shadow:0 0 0 #0000;clear:none;color:#1e1e1e;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;height:var(--checkbox-input-size);line-height:normal;line-height:0;margin:0 0 0 4px;outline:0;padding:6px 8px;padding:0!important;text-align:center;transition:none;vertical-align:top;width:var(--checkbox-input-size)}@media not (prefers-reduced-motion){.components-checkbox-control__input[type=checkbox]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-checkbox-control__input[type=checkbox]{font-size:13px;line-height:normal}}.components-checkbox-control__input[type=checkbox]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox]::-webkit-input-placeholder{color:#1e1e1e9e}.components-checkbox-control__input[type=checkbox]::-moz-placeholder{color:#1e1e1e9e}.components-checkbox-control__input[type=checkbox]:-ms-input-placeholder{color:#1e1e1e9e}.components-checkbox-control__input[type=checkbox]:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox]:checked{background:var(--wp-admin-theme-color);border-color:var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox]:checked::-ms-check{opacity:0}.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{color:#fff;margin:-3px -5px}@media (min-width:782px){.components-checkbox-control__input[type=checkbox]:checked:before,.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{margin:-4px -5px 0 0}}.components-checkbox-control__input[type=checkbox][aria-checked=mixed]{background:var(--wp-admin-theme-color);border-color:var(--wp-admin-theme-color)}.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{content:"\f460";display:inline-block;float:right;font:normal 30px/1 dashicons;vertical-align:middle;width:16px;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (min-width:782px){.components-checkbox-control__input[type=checkbox][aria-checked=mixed]:before{float:none;font-size:21px}}.components-checkbox-control__input[type=checkbox]:disabled,.components-checkbox-control__input[type=checkbox][aria-disabled=true]{background:#f0f0f0;border-color:#ddd;cursor:default;opacity:1}@media not (prefers-reduced-motion){.components-checkbox-control__input[type=checkbox]{transition:border-color .1s ease-in-out}}.components-checkbox-control__input[type=checkbox]:focus{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);outline:2px solid #0000;outline-offset:2px}.components-checkbox-control__input[type=checkbox]:checked,.components-checkbox-control__input[type=checkbox]:indeterminate{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-checkbox-control__input[type=checkbox]:checked::-ms-check,.components-checkbox-control__input[type=checkbox]:indeterminate::-ms-check{opacity:0}.components-checkbox-control__input[type=checkbox]:checked:before{content:none}.components-checkbox-control__input-container{aspect-ratio:1;display:inline-block;flex-shrink:0;line-height:1;margin-left:var(--checkbox-input-margin);position:relative;vertical-align:middle;width:var(--checkbox-input-size)}svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{--checkmark-size:var(--checkbox-input-size);fill:#fff;cursor:pointer;height:var(--checkmark-size);pointer-events:none;position:absolute;right:50%;top:50%;transform:translate(50%,-50%);-webkit-user-select:none;user-select:none;width:var(--checkmark-size)}@media (min-width:600px){svg.components-checkbox-control__checked,svg.components-checkbox-control__indeterminate{--checkmark-size:calc(var(--checkbox-input-size) + 4px)}}.components-checkbox-control__help{display:inline-block;margin-inline-start:calc(var(--checkbox-input-size) + var(--checkbox-input-margin))}.components-circular-option-picker{display:inline-block;min-width:188px;width:100%}.components-circular-option-picker .components-circular-option-picker__custom-clear-wrapper{display:flex;justify-content:flex-end;margin-top:12px}.components-circular-option-picker .components-circular-option-picker__swatches{display:flex;flex-wrap:wrap;gap:12px;position:relative;z-index:1}.components-circular-option-picker>:not(.components-circular-option-picker__swatches){position:relative;z-index:0}.components-circular-option-picker__option-wrapper{display:inline-block;height:28px;transform:scale(1);vertical-align:top;width:28px}@media not (prefers-reduced-motion){.components-circular-option-picker__option-wrapper{transition:transform .1s ease;will-change:transform}}.components-circular-option-picker__option-wrapper:hover{transform:scale(1.2)}.components-circular-option-picker__option-wrapper>div{height:100%;width:100%}.components-circular-option-picker__option-wrapper:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' fill='none'%3E%3Cpath fill='%23555D65' d='M6 8V6H4v2zm2 0V6h2v2zm2 8H8v-2h2zm2 0v-2h2v2zm0 2v-2h-2v2H8v2h2v-2zm2 0v2h-2v-2zm2 0h-2v-2h2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M18 18h2v-2h-2v-2h2v-2h-2v-2h2V8h-2v2h-2V8h-2v2h2v2h-2v2h2v2h2zm-2-4v-2h2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' d='M18 18v2h-2v-2z'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M8 10V8H6v2H4v2h2v2H4v2h2v2H4v2h2v2H4v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2v2h-2V4h-2v2h-2V4h-2v2h-2V4h-2v2h2v2h-2v2zm0 2v-2H6v2zm2 0v-2h2v2zm0 2v-2H8v2H6v2h2v2H6v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h-2v2h-2V6h-2v2h-2v2h2v2h-2v2z' clip-rule='evenodd'/%3E%3Cpath fill='%23555D65' fill-rule='evenodd' d='M4 0H2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v2H0v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2h-2V0h-2v2H8V0H6v2H4zm0 4V2H2v2zm2 0V2h2v2zm0 2V4H4v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2H2v2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h2V4h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2h-2V2h-2v2H8v2z' clip-rule='evenodd'/%3E%3C/svg%3E");border-radius:50%;bottom:1px;content:"";left:1px;position:absolute;right:1px;top:1px;z-index:-1}.components-circular-option-picker__option{aspect-ratio:1;background:#0000;border:none;border-radius:50%;box-shadow:inset 0 0 0 14px;cursor:pointer;display:inline-block;height:100%!important;vertical-align:top}@media not (prefers-reduced-motion){.components-circular-option-picker__option{transition:box-shadow .1s ease}}.components-circular-option-picker__option:hover{box-shadow:inset 0 0 0 14px!important}.components-circular-option-picker__option[aria-pressed=true],.components-circular-option-picker__option[aria-selected=true]{box-shadow:inset 0 0 0 4px;overflow:visible;position:relative;z-index:1}.components-circular-option-picker__option[aria-pressed=true]+svg,.components-circular-option-picker__option[aria-selected=true]+svg{border-radius:50%;pointer-events:none;position:absolute;right:2px;top:2px;z-index:2}.components-circular-option-picker__option:after{border:1px solid #0000;border-radius:50%;bottom:-1px;box-shadow:inset 0 0 0 1px #0003;box-sizing:inherit;content:"";left:-1px;position:absolute;right:-1px;top:-1px}.components-circular-option-picker__option:focus:after{border:2px solid #757575;border-radius:50%;box-shadow:inset 0 0 0 2px #fff;content:"";height:calc(100% + 4px);position:absolute;right:50%;top:50%;transform:translate(50%,-50%);width:calc(100% + 4px)}.components-circular-option-picker__option.components-button:focus{background-color:initial;box-shadow:inset 0 0 0 14px;outline:none}.components-circular-option-picker__button-action .components-circular-option-picker__option{background:#fff;color:#fff}.components-circular-option-picker__dropdown-link-action{margin-left:16px}.components-circular-option-picker__dropdown-link-action .components-button{line-height:22px}.components-palette-edit__popover-gradient-picker{padding:8px;width:260px}.components-dropdown-menu__menu .components-palette-edit__menu-button{width:100%}.component-color-indicator{background:#fff linear-gradient(45deg,#0000 48%,#ddd 0,#ddd 52%,#0000 0);border-radius:50%;box-shadow:inset 0 0 0 1px #0003;display:inline-block;height:20px;padding:0;width:20px}.components-combobox-control{width:100%}input.components-combobox-control__input[type=text]{border:none;box-shadow:none;font-family:inherit;font-size:16px;line-height:inherit;margin:0;min-height:auto;padding:2px;width:100%}@media (min-width:600px){input.components-combobox-control__input[type=text]{font-size:13px}}input.components-combobox-control__input[type=text]:focus{box-shadow:none;outline:none}.components-combobox-control__suggestions-container{align-items:flex-start;border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;display:flex;flex-wrap:wrap;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;line-height:normal;padding:0;width:100%}@media not (prefers-reduced-motion){.components-combobox-control__suggestions-container{transition:box-shadow .1s linear}}@media (min-width:600px){.components-combobox-control__suggestions-container{font-size:13px;line-height:normal}}.components-combobox-control__suggestions-container:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-combobox-control__suggestions-container::-webkit-input-placeholder{color:#1e1e1e9e}.components-combobox-control__suggestions-container::-moz-placeholder{color:#1e1e1e9e}.components-combobox-control__suggestions-container:-ms-input-placeholder{color:#1e1e1e9e}.components-combobox-control__suggestions-container:focus-within{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-combobox-control__suggestions-container .components-spinner{margin:0}.components-color-palette__custom-color-wrapper{position:relative;z-index:0}.components-color-palette__custom-color-button{background:none;border:none;border-radius:4px 4px 0 0;box-shadow:inset 0 0 0 1px #0003;box-sizing:border-box;cursor:pointer;height:64px;outline:1px solid #0000;position:relative;width:100%}.components-color-palette__custom-color-button:focus{box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline-width:2px}.components-color-palette__custom-color-button:after{background-image:repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0),repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0);background-position:0 0,24px 24px;background-size:48px 48px;border-radius:3px 3px 0 0;content:"";inset:1px;position:absolute;z-index:-1}.components-color-palette__custom-color-text-wrapper{border-radius:0 0 4px 4px;box-shadow:inset 0 -1px 0 0 #0003,inset -1px 0 0 0 #0003,inset 1px 0 0 0 #0003;font-size:13px;padding:12px 16px;position:relative}.components-color-palette__custom-color-name{color:var(--wp-components-color-foreground,#1e1e1e);margin:0 1px}.components-color-palette__custom-color-value{color:#757575}.components-color-palette__custom-color-value--is-hex{text-transform:uppercase}.components-color-palette__custom-color-value:empty:after{content:"";visibility:hidden}.components-custom-gradient-picker__gradient-bar{border-radius:2px;height:48px;position:relative;width:100%;z-index:1}.components-custom-gradient-picker__gradient-bar.has-gradient{background-image:repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0),repeating-linear-gradient(45deg,#e0e0e0 25%,#0000 0,#0000 75%,#e0e0e0 0,#e0e0e0);background-position:0 0,12px 12px;background-size:24px 24px}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__gradient-bar-background{inset:0;position:absolute}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__markers-container{margin-left:auto;margin-right:auto;position:relative;width:calc(100% - 48px)}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-dropdown{display:flex;height:16px;position:absolute;top:16px;width:16px}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown{background:#fff;border-radius:50%;color:#1e1e1e;height:inherit;min-width:16px!important;padding:2px;position:relative;width:inherit}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point-dropdown svg{height:100%;width:100%}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button{border-radius:50%;box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 2px 0 #00000040;height:inherit;outline:2px solid #0000;padding:0;width:inherit}.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button.is-active,.components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button:focus{box-shadow:inset 0 0 0 calc(var(--wp-admin-border-width-focus)*2) #fff,0 0 2px 0 #00000040;outline:1.5px solid #0000}.components-custom-gradient-picker__remove-control-point-wrapper{padding-bottom:8px}.components-custom-gradient-picker__inserter{direction:ltr}.components-custom-gradient-picker__liner-gradient-indicator{display:inline-block;flex:0 auto;height:20px;width:20px}.components-custom-gradient-picker__ui-line{position:relative;z-index:0}.block-editor-dimension-control .components-base-control__field{align-items:center;display:flex}.block-editor-dimension-control .components-base-control__label{align-items:center;display:flex;margin-bottom:0;margin-left:1em}.block-editor-dimension-control .components-base-control__label .dashicon{margin-left:.5em}.block-editor-dimension-control.is-manual .components-base-control__label{width:10em}body.is-dragging-components-draggable{cursor:move;cursor:grabbing!important}.components-draggable__invisible-drag-image{height:50px;position:fixed;right:-1000px;width:50px}.components-draggable__clone{background:#0000;padding:0;pointer-events:none;position:fixed;z-index:1000000000}.components-drop-zone{border-radius:2px;bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;visibility:hidden;z-index:40}.components-drop-zone.is-active{opacity:1;visibility:visible}.components-drop-zone .components-drop-zone__content{align-items:center;background-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));bottom:0;color:#fff;display:flex;height:100%;justify-content:center;left:0;opacity:0;pointer-events:none;position:absolute;right:0;text-align:center;top:0;width:100%;z-index:50}.components-drop-zone .components-drop-zone__content-inner{opacity:0;transform:scale(.9)}.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{opacity:1}@media not (prefers-reduced-motion){.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content{transition:opacity .2s ease-in-out}}.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{opacity:1;transform:scale(1)}@media not (prefers-reduced-motion){.components-drop-zone.is-active.is-dragging-over-element .components-drop-zone__content-inner{transition:opacity .1s ease-in-out .1s,transform .1s ease-in-out .1s}}.components-drop-zone__content-icon,.components-drop-zone__content-text{display:block}.components-drop-zone__content-icon{line-height:0;margin:0 auto 8px;fill:currentColor;pointer-events:none}.components-drop-zone__content-text{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.components-dropdown{display:inline-block}.components-dropdown__content .components-popover__content{padding:8px}.components-dropdown__content .components-popover__content:has(.components-menu-group){padding:0}.components-dropdown__content .components-popover__content:has(.components-menu-group) .components-dropdown-menu__menu>.components-menu-item__button,.components-dropdown__content .components-popover__content:has(.components-menu-group)>.components-menu-item__button{margin:8px;width:auto}.components-dropdown__content [role=menuitem]{white-space:nowrap}.components-dropdown__content .components-menu-group{padding:8px}.components-dropdown__content .components-menu-group+.components-menu-group{border-top:1px solid #ccc;padding:8px}.components-dropdown__content.is-alternate .components-menu-group+.components-menu-group{border-color:#1e1e1e}.components-dropdown-menu__toggle{vertical-align:top}.components-dropdown-menu__menu{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.4;width:100%}.components-dropdown-menu__menu .components-dropdown-menu__menu-item,.components-dropdown-menu__menu .components-menu-item{cursor:pointer;outline:none;padding:6px;white-space:nowrap;width:100%}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator,.components-dropdown-menu__menu .components-menu-item.has-separator{margin-top:6px;overflow:visible;position:relative}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.has-separator:before,.components-dropdown-menu__menu .components-menu-item.has-separator:before{background-color:#ddd;box-sizing:initial;content:"";display:block;height:1px;left:0;position:absolute;right:0;top:-3px}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-active svg,.components-dropdown-menu__menu .components-menu-item.is-active .dashicon,.components-dropdown-menu__menu .components-menu-item.is-active svg{background:#1e1e1e;border-radius:1px;box-shadow:0 0 0 1px #1e1e1e;color:#fff}.components-dropdown-menu__menu .components-dropdown-menu__menu-item.is-icon-only,.components-dropdown-menu__menu .components-menu-item.is-icon-only{width:auto}.components-dropdown-menu__menu .components-menu-item__button,.components-dropdown-menu__menu .components-menu-item__button.components-button{height:auto;min-height:40px;padding-left:8px;padding-right:8px;text-align:right}.components-duotone-picker__color-indicator:before{background:#0000}.components-duotone-picker__color-indicator>.components-button,.components-duotone-picker__color-indicator>.components-button.is-pressed:hover:not(:disabled){background:linear-gradient(45deg,#0000 48%,#ddd 0,#ddd 52%,#0000 0);color:#0000}.components-duotone-picker__color-indicator>.components-button:not([aria-disabled=true]):active{color:#0000}.components-color-list-picker,.components-color-list-picker__swatch-button{width:100%}.components-color-list-picker__color-picker{margin:8px 0}.components-color-list-picker__swatch-color{margin:2px}.components-external-link{text-decoration:none}.components-external-link__contents{text-decoration:underline}.components-external-link__icon{font-weight:400;margin-right:.5ch}.components-form-toggle{display:inline-block;height:16px;position:relative}.components-form-toggle .components-form-toggle__track{background-color:#fff;border:1px solid #949494;border-radius:8px;box-sizing:border-box;content:"";display:inline-block;height:16px;overflow:hidden;position:relative;vertical-align:top;width:32px}@media not (prefers-reduced-motion){.components-form-toggle .components-form-toggle__track{transition:background-color .2s ease,border-color .2s ease}}.components-form-toggle .components-form-toggle__track:after{border-top:16px solid #0000;box-sizing:border-box;content:"";inset:0;opacity:0;position:absolute}@media not (prefers-reduced-motion){.components-form-toggle .components-form-toggle__track:after{transition:opacity .2s ease}}.components-form-toggle .components-form-toggle__thumb{background-color:#1e1e1e;border:6px solid #0000;border-radius:50%;box-shadow:0 1px 1px #00000008,0 1px 2px #00000005,0 3px 3px #00000005,0 4px 4px #00000003;box-sizing:border-box;display:block;height:12px;position:absolute;right:2px;top:2px;width:12px}@media not (prefers-reduced-motion){.components-form-toggle .components-form-toggle__thumb{transition:transform .2s ease,background-color .2s ease-out}}.components-form-toggle.is-checked .components-form-toggle__track{background-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-form-toggle.is-checked .components-form-toggle__track:after{opacity:1}.components-form-toggle .components-form-toggle__input:focus+.components-form-toggle__track{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000;outline-offset:2px}.components-form-toggle.is-checked .components-form-toggle__thumb{background-color:#fff;border-width:0;transform:translateX(-16px)}.components-disabled .components-form-toggle,.components-form-toggle.is-disabled{opacity:.3}.components-form-toggle input.components-form-toggle__input[type=checkbox]{border:none;height:100%;margin:0;opacity:0;padding:0;position:absolute;right:0;top:0;width:100%;z-index:1}.components-form-toggle input.components-form-toggle__input[type=checkbox]:checked{background:none}.components-form-toggle input.components-form-toggle__input[type=checkbox]:before{content:""}.components-form-toggle input.components-form-toggle__input[type=checkbox]:not(:disabled,[aria-disabled=true]){cursor:pointer}.components-form-token-field__input-container{border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;cursor:text;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;line-height:normal;padding:0;width:100%}@media not (prefers-reduced-motion){.components-form-token-field__input-container{transition:box-shadow .1s linear}}@media (min-width:600px){.components-form-token-field__input-container{font-size:13px;line-height:normal}}.components-form-token-field__input-container:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-form-token-field__input-container::-webkit-input-placeholder{color:#1e1e1e9e}.components-form-token-field__input-container::-moz-placeholder{color:#1e1e1e9e}.components-form-token-field__input-container:-ms-input-placeholder{color:#1e1e1e9e}.components-form-token-field__input-container.is-disabled{background:#ddd;border-color:#ddd}.components-form-token-field__input-container.is-active{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-form-token-field__input-container input[type=text].components-form-token-field__input{background:inherit;border:0;box-shadow:none;color:#1e1e1e;display:inline-block;flex:1;font-family:inherit;font-size:16px;margin-right:4px;max-width:100%;min-height:24px;min-width:50px;padding:0;width:100%}@media (min-width:600px){.components-form-token-field__input-container input[type=text].components-form-token-field__input{font-size:13px}}.components-form-token-field.is-active .components-form-token-field__input-container input[type=text].components-form-token-field__input,.components-form-token-field__input-container input[type=text].components-form-token-field__input:focus{box-shadow:none;outline:none}.components-form-token-field__input-container .components-form-token-field__token+input[type=text].components-form-token-field__input{width:auto}.components-form-token-field__token{color:#1e1e1e;display:flex;font-size:13px;max-width:100%}.components-form-token-field__token.is-success .components-form-token-field__remove-token,.components-form-token-field__token.is-success .components-form-token-field__token-text{background:#4ab866}.components-form-token-field__token.is-error .components-form-token-field__remove-token,.components-form-token-field__token.is-error .components-form-token-field__token-text{background:#cc1818}.components-form-token-field__token.is-validating .components-form-token-field__remove-token,.components-form-token-field__token.is-validating .components-form-token-field__token-text{color:#757575}.components-form-token-field__token.is-borderless{padding:0 0 0 24px;position:relative}.components-form-token-field__token.is-borderless .components-form-token-field__token-text{background:#0000}.components-form-token-field__token.is-borderless:not(.is-disabled) .components-form-token-field__token-text{color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-form-token-field__token.is-borderless .components-form-token-field__remove-token{background:#0000;color:#757575;left:0;position:absolute;top:1px}.components-form-token-field__token.is-borderless.is-success .components-form-token-field__token-text{color:#4ab866}.components-form-token-field__token.is-borderless.is-error .components-form-token-field__token-text{color:#cc1818;padding:0 6px 0 4px}.components-form-token-field__token.is-borderless.is-validating .components-form-token-field__token-text{color:#1e1e1e}.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{background:#ddd;display:inline-block;height:auto;min-width:unset}@media not (prefers-reduced-motion){.components-form-token-field__remove-token.components-button,.components-form-token-field__token-text{transition:all .2s cubic-bezier(.4,1,.4,1)}}.components-form-token-field__token-text{border-radius:0 1px 1px 0;line-height:24px;overflow:hidden;padding:0 8px 0 0;text-overflow:ellipsis;white-space:nowrap}.components-form-token-field__remove-token.components-button{border-radius:1px 0 0 1px;color:#1e1e1e;line-height:10px;overflow:initial}.components-form-token-field__remove-token.components-button:hover:not(:disabled){color:#1e1e1e}.components-form-token-field__suggestions-list{box-shadow:inset 0 1px 0 0 #949494;flex:1 0 100%;list-style:none;margin:0;max-height:128px;min-width:100%;overflow-y:auto;padding:0}@media not (prefers-reduced-motion){.components-form-token-field__suggestions-list{transition:all .15s ease-in-out}}.components-form-token-field__suggestion{box-sizing:border-box;color:#1e1e1e;display:block;font-size:13px;margin:0;min-height:32px;padding:8px 12px}.components-form-token-field__suggestion.is-selected{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:#fff}.components-form-token-field__suggestion[aria-disabled=true]{color:#949494;pointer-events:none}.components-form-token-field__suggestion[aria-disabled=true].is-selected{background-color:rgba(var(--wp-components-color-accent--rgb,var(--wp-admin-theme-color--rgb)),.04)}.components-form-token-field__suggestion:not(.is-empty){cursor:pointer}@media (min-width:600px){.components-guide{width:600px}}.components-guide .components-modal__content{margin-top:0;padding:0}.components-guide .components-modal__content:before{content:none}.components-guide .components-modal__header{border-bottom:none;height:60px;padding:0;position:sticky}.components-guide .components-modal__header .components-button{align-self:flex-start;margin:8px 0 0 8px;position:static}.components-guide .components-modal__header .components-button:hover svg{fill:#fff}.components-guide .components-guide__container{display:flex;flex-direction:column;justify-content:space-between;margin-top:-60px;min-height:100%}.components-guide .components-guide__page{display:flex;flex-direction:column;justify-content:center;position:relative}@media (min-width:600px){.components-guide .components-guide__page{min-height:300px}}.components-guide .components-guide__footer{align-content:center;display:flex;height:36px;justify-content:center;margin:0 0 24px;padding:0 32px;position:relative;width:100%}.components-guide .components-guide__page-control{margin:0;text-align:center}.components-guide .components-guide__page-control li{display:inline-block;margin:0}.components-guide .components-guide__page-control .components-button{color:#e0e0e0;margin:-6px 0}.components-guide .components-guide__page-control li[aria-current=step] .components-button{color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-modal__frame.components-guide{border:none;max-height:575px;min-width:312px}@media (max-width:600px){.components-modal__frame.components-guide{margin:auto;max-width:calc(100vw - 32px)}}.components-button.components-guide__back-button,.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{position:absolute}.components-button.components-guide__back-button{right:32px}.components-button.components-guide__finish-button,.components-button.components-guide__forward-button{left:32px}[role=region]{position:relative}.is-focusing-regions [role=region]:focus:after,[role=region].interface-interface-skeleton__content:focus-visible:after{bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:1000000}.is-focusing-regions .editor-post-publish-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-entities-saved-states-panel,.is-focusing-regions .interface-interface-skeleton__actions .editor-layout__toggle-publish-panel,.is-focusing-regions .interface-interface-skeleton__sidebar .editor-layout__toggle-sidebar-panel,.is-focusing-regions [role=region]:focus:after,.is-focusing-regions.is-distraction-free .interface-interface-skeleton__header .edit-post-header,[role=region].interface-interface-skeleton__content:focus-visible:after{outline-color:var(--wp-admin-theme-color);outline-offset:calc(((-1*var(--wp-admin-border-width-focus))/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2);outline-style:solid;outline-width:calc((var(--wp-admin-border-width-focus)/var(--wp-block-editor-iframe-zoom-out-scale, 1))*2)}.components-menu-group+.components-menu-group{border-top:1px solid #1e1e1e;padding-top:8px}.components-menu-group+.components-menu-group.has-hidden-separator{border-top:none;margin-top:0;padding-top:0}.components-menu-group:has(>div:empty){display:none}.components-menu-group__label{color:#757575;font-size:11px;font-weight:500;margin-bottom:12px;margin-top:4px;padding:0 8px;text-transform:uppercase;white-space:nowrap}.components-menu-item__button,.components-menu-item__button.components-button{width:100%}.components-menu-item__button.components-button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button.components-button[role=menuitemradio] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemcheckbox] .components-menu-item__item:only-child,.components-menu-item__button[role=menuitemradio] .components-menu-item__item:only-child{box-sizing:initial;padding-left:48px}.components-menu-item__button .components-menu-items__item-icon,.components-menu-item__button.components-button .components-menu-items__item-icon{display:inline-block;flex:0 0 auto}.components-menu-item__button .components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-items__item-icon.has-icon-right{margin-left:-2px;margin-right:24px}.components-menu-item__button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right,.components-menu-item__button.components-button .components-menu-item__shortcut+.components-menu-items__item-icon.has-icon-right{margin-right:8px}.components-menu-item__button .block-editor-block-icon,.components-menu-item__button.components-button .block-editor-block-icon{margin-left:8px;margin-right:-2px}.components-menu-item__button.components-button.is-primary,.components-menu-item__button.is-primary{justify-content:center}.components-menu-item__button.components-button.is-primary .components-menu-item__item,.components-menu-item__button.is-primary .components-menu-item__item{margin-left:0}.components-menu-item__button.components-button:disabled.is-tertiary,.components-menu-item__button.components-button[aria-disabled=true].is-tertiary,.components-menu-item__button:disabled.is-tertiary,.components-menu-item__button[aria-disabled=true].is-tertiary{background:none;color:var(--wp-components-color-accent-darker-10,var(--wp-admin-theme-color-darker-10,#2145e6));opacity:.3}.components-menu-item__info-wrapper{display:flex;flex-direction:column;margin-left:auto}.components-menu-item__info{color:#757575;font-size:12px;margin-top:4px;white-space:normal}.components-menu-item__item{align-items:center;display:inline-flex;margin-left:auto;min-width:160px;white-space:nowrap}.components-menu-item__shortcut{align-self:center;color:currentColor;display:none;margin-left:0;margin-right:auto;padding-right:24px}@media (min-width:480px){.components-menu-item__shortcut{display:inline}}.components-menu-items-choice,.components-menu-items-choice.components-button{height:auto;min-height:40px}.components-menu-items-choice svg,.components-menu-items-choice.components-button svg{margin-left:12px}.components-menu-items-choice.components-button.has-icon,.components-menu-items-choice.has-icon{padding-right:12px}.components-modal__screen-overlay{background-color:#00000059;bottom:0;display:flex;left:0;position:fixed;right:0;top:0;z-index:100000}@keyframes __wp-base-styles-fade-in{0%{opacity:0}to{opacity:1}}@media not (prefers-reduced-motion){.components-modal__screen-overlay{animation:__wp-base-styles-fade-in .08s linear 0s;animation-fill-mode:forwards}}@keyframes __wp-base-styles-fade-out{0%{opacity:1}to{opacity:0}}@media not (prefers-reduced-motion){.components-modal__screen-overlay.is-animating-out{animation:__wp-base-styles-fade-out .08s linear 80ms;animation-fill-mode:forwards}}.components-modal__frame{animation-fill-mode:forwards;animation-name:components-modal__appear-animation;animation-timing-function:cubic-bezier(.29,0,0,1);background:#fff;border-radius:8px 8px 0 0;box-shadow:0 5px 15px #00000014,0 15px 27px #00000012,0 30px 36px #0000000a,0 50px 43px #00000005;box-sizing:border-box;display:flex;margin:40px 0 0;overflow:hidden;width:100%}.components-modal__frame *,.components-modal__frame :after,.components-modal__frame :before{box-sizing:inherit}@media not (prefers-reduced-motion){.components-modal__frame{animation-duration:var(--modal-frame-animation-duration)}}.components-modal__screen-overlay.is-animating-out .components-modal__frame{animation-name:components-modal__disappear-animation;animation-timing-function:cubic-bezier(1,0,.2,1)}@media (min-width:600px){.components-modal__frame{border-radius:8px;margin:auto;max-height:calc(100% - 120px);max-width:calc(100% - 32px);min-width:350px;width:auto}}@media (min-width:600px) and (min-width:600px){.components-modal__frame.is-full-screen{height:calc(100% - 32px);max-height:none;width:calc(100% - 32px)}}@media (min-width:600px) and (min-width:782px){.components-modal__frame.is-full-screen{height:calc(100% - 80px);max-width:none;width:calc(100% - 80px)}}@media (min-width:600px){.components-modal__frame.has-size-large,.components-modal__frame.has-size-medium,.components-modal__frame.has-size-small{width:100%}.components-modal__frame.has-size-small{max-width:384px}.components-modal__frame.has-size-medium{max-width:512px}.components-modal__frame.has-size-large{max-width:840px}}@media (min-width:960px){.components-modal__frame{max-height:70%}}@keyframes components-modal__appear-animation{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}@keyframes components-modal__disappear-animation{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.9)}}.components-modal__header{align-items:center;border-bottom:1px solid #0000;box-sizing:border-box;display:flex;flex-direction:row;height:72px;justify-content:space-between;padding:24px 32px 8px;position:absolute;right:0;top:0;width:100%;z-index:10}.components-modal__header .components-modal__header-heading{font-size:1.2rem;font-weight:600}.components-modal__header h1{line-height:1;margin:0}.components-modal__content.has-scrolled-content:not(.hide-header) .components-modal__header{border-bottom-color:#ddd}.components-modal__header+p{margin-top:0}.components-modal__header-heading-container{align-items:center;display:flex;flex-direction:row;flex-grow:1;justify-content:right}.components-modal__header-icon-container{display:inline-block}.components-modal__header-icon-container svg{max-height:36px;max-width:36px;padding:8px}.components-modal__content{flex:1;margin-top:72px;overflow:auto;padding:4px 32px 32px}.components-modal__content.hide-header{margin-top:0;padding-top:32px}.components-modal__content.is-scrollable:focus-visible{box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000;outline-offset:-2px}.components-notice{align-items:center;background-color:#fff;border-right:4px solid var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));color:#1e1e1e;display:flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;padding:8px 12px}.components-notice.is-dismissible{position:relative}.components-notice.is-success{background-color:#eff9f1;border-right-color:#4ab866}.components-notice.is-warning{background-color:#fef8ee;border-right-color:#f0b849}.components-notice.is-error{background-color:#f4a2a2;border-right-color:#cc1818}.components-notice__content{flex-grow:1;margin:4px 0 4px 25px}.components-notice__actions{display:flex;flex-wrap:wrap}.components-notice__action.components-button{margin-left:8px}.components-notice__action.components-button,.components-notice__action.components-button.is-link{margin-right:12px}.components-notice__action.components-button.is-secondary{vertical-align:initial}.components-notice__dismiss{align-self:flex-start;color:#757575;flex-shrink:0}.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):focus,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):active,.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{background-color:initial;color:#1e1e1e}.components-notice__dismiss:not(:disabled):not([aria-disabled=true]):not(.is-secondary):hover{box-shadow:none}.components-notice-list{box-sizing:border-box;max-width:100vw}.components-notice-list .components-notice__content{line-height:2;margin-bottom:12px;margin-top:12px}.components-notice-list .components-notice__action.components-button{display:block;margin-right:0;margin-top:8px}.components-panel{background:#fff;border:1px solid #e0e0e0}.components-panel>.components-panel__body:first-child,.components-panel>.components-panel__header:first-child{margin-top:-1px}.components-panel>.components-panel__body:last-child,.components-panel>.components-panel__header:last-child{border-bottom-width:0}.components-panel+.components-panel{margin-top:-1px}.components-panel__body{border-bottom:1px solid #e0e0e0;border-top:1px solid #e0e0e0}.components-panel__body h3{margin:0 0 .5em}.components-panel__body.is-opened{padding:16px}.components-panel__header{align-items:center;border-bottom:1px solid #ddd;box-sizing:initial;display:flex;flex-shrink:0;height:47px;justify-content:space-between;padding:0 16px}.components-panel__header h2{color:inherit;font-size:inherit;margin:0}.components-panel__body+.components-panel__body,.components-panel__body+.components-panel__header,.components-panel__header+.components-panel__body,.components-panel__header+.components-panel__header{margin-top:-1px}.components-panel__body>.components-panel__body-title{display:block;font-size:inherit;margin-bottom:0;margin-top:0;padding:0}@media not (prefers-reduced-motion){.components-panel__body>.components-panel__body-title{transition:background .1s ease-in-out}}.components-panel__body.is-opened>.components-panel__body-title{margin:-16px -16px 5px}.components-panel__body>.components-panel__body-title:hover{background:#f0f0f0;border:none}.components-panel__body-toggle.components-button{border:none;box-shadow:none;color:#1e1e1e;font-weight:500;height:auto;outline:none;padding:16px 16px 16px 48px;position:relative;text-align:right;width:100%}@media not (prefers-reduced-motion){.components-panel__body-toggle.components-button{transition:background .1s ease-in-out}}.components-panel__body-toggle.components-button:focus{border-radius:0;box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-panel__body-toggle.components-button .components-panel__arrow{color:#1e1e1e;left:16px;position:absolute;top:50%;transform:translateY(-50%);fill:currentColor}@media not (prefers-reduced-motion){.components-panel__body-toggle.components-button .components-panel__arrow{transition:color .1s ease-in-out}}body.rtl .components-panel__body-toggle.components-button .dashicons-arrow-right{-ms-filter:fliph;filter:FlipH;margin-top:-10px;transform:scaleX(-1)}.components-panel__icon{color:#757575;margin:-2px 6px -2px 0}.components-panel__body-toggle-icon{margin-left:-5px}.components-panel__color-title{float:right;height:19px}.components-panel__row{align-items:center;display:flex;justify-content:space-between;margin-top:8px;min-height:36px}.components-panel__row select{min-width:0}.components-panel__row label{flex-shrink:0;margin-left:12px;max-width:75%}.components-panel__row:empty,.components-panel__row:first-of-type{margin-top:0}.components-panel .circle-picker{padding-bottom:20px}.components-placeholder.components-placeholder{align-items:flex-start;box-sizing:border-box;color:#1e1e1e;display:flex;flex-direction:column;font-size:13px;gap:16px;margin:0;padding:24px;position:relative;text-align:right;width:100%;-moz-font-smoothing:subpixel-antialiased;-webkit-font-smoothing:subpixel-antialiased;background-color:#fff;border-radius:2px;box-shadow:inset 0 0 0 1px #1e1e1e;outline:1px solid #0000}.components-placeholder__error,.components-placeholder__fieldset,.components-placeholder__instructions,.components-placeholder__label{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;font-weight:400;letter-spacing:normal;line-height:normal;text-transform:none}.components-placeholder__label{align-items:center;display:flex;font-weight:600}.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{margin-left:4px;fill:currentColor}@media (forced-colors:active){.components-placeholder__label .block-editor-block-icon,.components-placeholder__label .dashicon,.components-placeholder__label>svg{fill:CanvasText}}.components-placeholder__label:empty{display:none}.components-placeholder__fieldset,.components-placeholder__fieldset form{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px;justify-content:flex-start;width:100%}.components-placeholder__fieldset form p,.components-placeholder__fieldset p{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.components-placeholder__fieldset.is-column-layout,.components-placeholder__fieldset.is-column-layout form{flex-direction:column}.components-placeholder__input[type=url]{border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;flex:1 1 auto;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;line-height:normal;padding:6px 8px}@media not (prefers-reduced-motion){.components-placeholder__input[type=url]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-placeholder__input[type=url]{font-size:13px;line-height:normal}}.components-placeholder__input[type=url]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-placeholder__input[type=url]::-webkit-input-placeholder{color:#1e1e1e9e}.components-placeholder__input[type=url]::-moz-placeholder{color:#1e1e1e9e}.components-placeholder__input[type=url]:-ms-input-placeholder{color:#1e1e1e9e}.components-placeholder__error{gap:8px;width:100%}.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link{margin-left:10px;margin-right:10px}.components-placeholder__fieldset .components-button:not(.is-link)~.components-button.is-link:last-child{margin-left:0}.components-placeholder.is-medium .components-placeholder__instructions,.components-placeholder.is-small .components-placeholder__instructions{display:none}.components-placeholder.is-medium .components-placeholder__fieldset,.components-placeholder.is-medium .components-placeholder__fieldset form,.components-placeholder.is-small .components-placeholder__fieldset,.components-placeholder.is-small .components-placeholder__fieldset form{flex-direction:column}.components-placeholder.is-medium .components-button,.components-placeholder.is-medium .components-placeholder__fieldset>*,.components-placeholder.is-small .components-button,.components-placeholder.is-small .components-placeholder__fieldset>*{justify-content:center;width:100%}.components-placeholder.is-small{padding:16px}.components-placeholder.has-illustration{-webkit-backdrop-filter:blur(100px);backdrop-filter:blur(100px);backface-visibility:hidden;background-color:initial;border-radius:0;box-shadow:none;color:inherit;display:flex;overflow:hidden}.is-dark-theme .components-placeholder.has-illustration{background-color:#0000001a}.components-placeholder.has-illustration .components-placeholder__fieldset{margin-left:0;margin-right:0}.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{opacity:0;pointer-events:none}@media not (prefers-reduced-motion){.components-placeholder.has-illustration .components-button,.components-placeholder.has-illustration .components-placeholder__instructions,.components-placeholder.has-illustration .components-placeholder__label{transition:opacity .1s linear}}.is-selected>.components-placeholder.has-illustration .components-button,.is-selected>.components-placeholder.has-illustration .components-placeholder__instructions,.is-selected>.components-placeholder.has-illustration .components-placeholder__label{opacity:1;pointer-events:auto}.components-placeholder.has-illustration:before{background:currentColor;bottom:0;content:"";left:0;opacity:.1;pointer-events:none;position:absolute;right:0;top:0}.is-selected .components-placeholder.has-illustration{overflow:auto}.components-placeholder__preview{display:flex;justify-content:center}.components-placeholder__illustration{box-sizing:initial;height:100%;position:absolute;right:50%;top:50%;transform:translate(50%,-50%);width:100%;stroke:currentColor;opacity:.25}.components-popover{box-sizing:border-box;will-change:transform;z-index:1000000}.components-popover *,.components-popover :after,.components-popover :before{box-sizing:inherit}.components-popover.is-expanded{bottom:0;left:0;position:fixed;right:0;top:0;z-index:1000000!important}.components-popover__content{background:#fff;border-radius:4px;box-shadow:0 0 0 1px #ccc,0 2px 3px #0000000d,0 4px 5px #0000000a,0 12px 12px #00000008,0 16px 16px #00000005;box-sizing:border-box;width:min-content}.is-alternate .components-popover__content{border-radius:2px;box-shadow:0 0 0 1px #1e1e1e}.is-unstyled .components-popover__content{background:none;border-radius:0;box-shadow:none}.components-popover.is-expanded .components-popover__content{box-shadow:0 -1px 0 0 #ccc;height:calc(100% - 48px);overflow-y:visible;position:static;width:auto}.components-popover.is-expanded.is-alternate .components-popover__content{box-shadow:0 -1px 0 #1e1e1e}.components-popover__header{align-items:center;background:#fff;display:flex;height:48px;justify-content:space-between;padding:0 16px 0 8px}.components-popover__header-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.components-popover__close.components-button{z-index:5}.components-popover__arrow{display:flex;height:14px;pointer-events:none;position:absolute;width:14px}.components-popover__arrow:before{background-color:#fff;content:"";height:2px;left:1px;position:absolute;right:1px;top:-1px}.components-popover__arrow.is-top{bottom:-14px!important;transform:rotate(0)}.components-popover__arrow.is-right{left:-14px!important;transform:rotate(90deg)}.components-popover__arrow.is-bottom{top:-14px!important;transform:rotate(180deg)}.components-popover__arrow.is-left{right:-14px!important;transform:rotate(-90deg)}.components-popover__triangle{display:block;flex:1}.components-popover__triangle-bg{fill:#fff}.components-popover__triangle-border{fill:#0000;stroke-width:1px;stroke:#ccc}.is-alternate .components-popover__triangle-border{stroke:#1e1e1e}.components-radio-control{border:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;margin:0;padding:0}.components-radio-control__group-wrapper.has-help{margin-block-end:12px}.components-radio-control__option{align-items:center;column-gap:8px;display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto minmax(0,max-content)}.components-radio-control__input[type=radio]{appearance:none;border:1px solid #1e1e1e;border-radius:2px;border-radius:50%;box-shadow:0 0 0 #0000;cursor:pointer;display:inline-flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;grid-column:1;grid-row:1;height:24px;line-height:normal;margin:0;max-width:24px;min-width:24px;padding:0;position:relative;transition:none;width:24px}@media not (prefers-reduced-motion){.components-radio-control__input[type=radio]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-radio-control__input[type=radio]{font-size:13px;line-height:normal}}.components-radio-control__input[type=radio]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color)}.components-radio-control__input[type=radio]::-webkit-input-placeholder{color:#1e1e1e9e}.components-radio-control__input[type=radio]::-moz-placeholder{color:#1e1e1e9e}.components-radio-control__input[type=radio]:-ms-input-placeholder{color:#1e1e1e9e}@media (min-width:600px){.components-radio-control__input[type=radio]{height:16px;max-width:16px;min-width:16px;width:16px}}.components-radio-control__input[type=radio]:checked:before{background-color:#fff;border:4px solid #fff;box-sizing:inherit;height:12px;margin:0;position:absolute;right:50%;top:50%;transform:translate(50%,-50%);width:12px}@media (min-width:600px){.components-radio-control__input[type=radio]:checked:before{height:8px;width:8px}}.components-radio-control__input[type=radio]:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--wp-admin-theme-color)}.components-radio-control__input[type=radio]:checked{background:var(--wp-admin-theme-color);border:none}.components-radio-control__input[type=radio]:focus{box-shadow:0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 0 calc(var(--wp-admin-border-width-focus)*2) var(--wp-admin-theme-color);outline:2px solid #0000;outline-offset:2px}.components-radio-control__input[type=radio]:checked{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-color:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-radio-control__input[type=radio]:checked:before{border-radius:50%;content:""}.components-radio-control__label{cursor:pointer;grid-column:2;grid-row:1;line-height:24px}@media (min-width:600px){.components-radio-control__label{line-height:16px}}.components-radio-control__option-description{grid-column:2;grid-row:2;padding-block-start:4px}.components-radio-control__option-description.components-radio-control__option-description{margin-top:0}.components-resizable-box__handle{display:none;height:23px;width:23px;z-index:2}.components-resizable-box__container.has-show-handle .components-resizable-box__handle{display:block}.components-resizable-box__handle>div{height:100%;outline:none;position:relative;width:100%;z-index:2}.components-resizable-box__container>img{width:inherit}.components-resizable-box__handle:after{background:#fff;border-radius:50%;box-shadow:inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),0 1px 1px #00000008,0 1px 2px #00000005,0 3px 3px #00000005,0 4px 4px #00000003;content:"";cursor:inherit;display:block;height:15px;left:calc(50% - 8px);outline:2px solid #0000;position:absolute;top:calc(50% - 8px);width:15px}.components-resizable-box__side-handle:before{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-radius:9999px;content:"";cursor:inherit;display:block;height:3px;left:calc(50% - 1px);opacity:0;position:absolute;top:calc(50% - 1px);width:3px}@media not (prefers-reduced-motion){.components-resizable-box__side-handle:before{transition:transform .1s ease-in;will-change:transform}}.components-resizable-box__corner-handle,.components-resizable-box__side-handle{z-index:2}.components-resizable-box__side-handle.components-resizable-box__handle-bottom,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:before,.components-resizable-box__side-handle.components-resizable-box__handle-top,.components-resizable-box__side-handle.components-resizable-box__handle-top:before{border-left:0;border-right:0;right:0;width:100%}.components-resizable-box__side-handle.components-resizable-box__handle-left,.components-resizable-box__side-handle.components-resizable-box__handle-left:before,.components-resizable-box__side-handle.components-resizable-box__handle-right,.components-resizable-box__side-handle.components-resizable-box__handle-right:before{border-bottom:0;border-top:0;height:100%;top:0}@media not (prefers-reduced-motion){.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{animation:components-resizable-box__top-bottom-animation .1s ease-out 0s;animation-fill-mode:forwards}.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before{animation:components-resizable-box__left-right-animation .1s ease-out 0s;animation-fill-mode:forwards}}@media not all and (min-resolution:0.001dpcm){@supports (-webkit-appearance:none){.components-resizable-box__side-handle.components-resizable-box__handle-bottom:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-bottom:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-left:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-right:hover:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:active:before,.components-resizable-box__side-handle.components-resizable-box__handle-top:hover:before{animation:none}}}@keyframes components-resizable-box__top-bottom-animation{0%{opacity:0;transform:scaleX(0)}to{opacity:1;transform:scaleX(1)}}@keyframes components-resizable-box__left-right-animation{0%{opacity:0;transform:scaleY(0)}to{opacity:1;transform:scaleY(1)}}.components-resizable-box__handle-right{right:-11.5px}.components-resizable-box__handle-left{left:-11.5px}.components-resizable-box__handle-top{top:-11.5px}.components-resizable-box__handle-bottom{bottom:-11.5px}.components-responsive-wrapper{align-items:center;display:flex;justify-content:center;max-width:100%;position:relative}.components-responsive-wrapper__content{display:block;max-width:100%;width:100%}.components-sandbox{overflow:hidden}iframe.components-sandbox{width:100%}body.lockscroll,html.lockscroll{overflow:hidden}.components-select-control__input{outline:0;-webkit-tap-highlight-color:rgba(0,0,0,0)!important}@media (max-width:782px){.components-base-control .components-base-control__field .components-select-control__input{font-size:16px}}.components-snackbar{-webkit-backdrop-filter:blur(16px) saturate(180%);backdrop-filter:blur(16px) saturate(180%);background:#000000d9;border-radius:4px;box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;box-sizing:border-box;color:#fff;cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;max-width:600px;padding:12px 20px;pointer-events:auto;width:100%}@media (min-width:600px){.components-snackbar{width:fit-content}}.components-snackbar:focus{box-shadow:inset 0 0 0 1px #fff,0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))}.components-snackbar.components-snackbar-explicit-dismiss{cursor:default}.components-snackbar .components-snackbar__content-with-icon{padding-right:24px;position:relative}.components-snackbar .components-snackbar__icon{position:absolute;right:-8px;top:-2.9px}.components-snackbar .components-snackbar__dismiss-button{cursor:pointer;margin-right:24px}.components-snackbar__action.components-button{color:#fff;flex-shrink:0;margin-right:32px}.components-snackbar__action.components-button:focus{box-shadow:none;outline:1px dotted #fff}.components-snackbar__action.components-button:hover{color:currentColor;text-decoration:none}.components-snackbar__content{align-items:baseline;display:flex;justify-content:space-between;line-height:1.4}.components-snackbar-list{box-sizing:border-box;pointer-events:none;position:absolute;width:100%;z-index:100000}.components-snackbar-list__notice-container{padding-top:8px;position:relative}.components-tab-panel__tabs{align-items:stretch;display:flex;flex-direction:row}.components-tab-panel__tabs[aria-orientation=vertical]{flex-direction:column}.components-tab-panel__tabs-item{background:#0000;border:none;border-radius:0;box-shadow:none;cursor:pointer;font-weight:500;height:48px!important;margin-right:0;padding:3px 16px;position:relative}.components-tab-panel__tabs-item:focus:not(:disabled){box-shadow:none;outline:none;position:relative}.components-tab-panel__tabs-item:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));border-radius:0;bottom:0;content:"";height:calc(var(--wp-admin-border-width-focus)*0);left:0;pointer-events:none;position:absolute;right:0}@media not (prefers-reduced-motion){.components-tab-panel__tabs-item:after{transition:all .1s linear}}.components-tab-panel__tabs-item.is-active:after{height:calc(var(--wp-admin-border-width-focus)*1);outline:2px solid #0000;outline-offset:-1px}.components-tab-panel__tabs-item:before{border-radius:2px;bottom:12px;box-shadow:0 0 0 0 #0000;content:"";left:12px;pointer-events:none;position:absolute;right:12px;top:12px}@media not (prefers-reduced-motion){.components-tab-panel__tabs-item:before{transition:all .1s linear}}.components-tab-panel__tabs-item:focus-visible:before{box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000}.components-tab-panel__tab-content:focus{box-shadow:none;outline:none}.components-tab-panel__tab-content:focus-visible{box-shadow:0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9));outline:2px solid #0000;outline-offset:0}.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{border:1px solid #949494;border-radius:2px;box-shadow:0 0 0 #0000;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:16px;height:32px;line-height:normal;margin:0;padding:6px 8px;width:100%}@media not (prefers-reduced-motion){.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{transition:box-shadow .1s linear}}@media (min-width:600px){.components-text-control__input,.components-text-control__input[type=color],.components-text-control__input[type=date],.components-text-control__input[type=datetime-local],.components-text-control__input[type=datetime],.components-text-control__input[type=email],.components-text-control__input[type=month],.components-text-control__input[type=number],.components-text-control__input[type=password],.components-text-control__input[type=tel],.components-text-control__input[type=text],.components-text-control__input[type=time],.components-text-control__input[type=url],.components-text-control__input[type=week]{font-size:13px;line-height:normal}}.components-text-control__input:focus,.components-text-control__input[type=color]:focus,.components-text-control__input[type=date]:focus,.components-text-control__input[type=datetime-local]:focus,.components-text-control__input[type=datetime]:focus,.components-text-control__input[type=email]:focus,.components-text-control__input[type=month]:focus,.components-text-control__input[type=number]:focus,.components-text-control__input[type=password]:focus,.components-text-control__input[type=tel]:focus,.components-text-control__input[type=text]:focus,.components-text-control__input[type=time]:focus,.components-text-control__input[type=url]:focus,.components-text-control__input[type=week]:focus{border-color:var(--wp-admin-theme-color);box-shadow:0 0 0 .5px var(--wp-admin-theme-color);outline:2px solid #0000}.components-text-control__input::-webkit-input-placeholder,.components-text-control__input[type=color]::-webkit-input-placeholder,.components-text-control__input[type=date]::-webkit-input-placeholder,.components-text-control__input[type=datetime-local]::-webkit-input-placeholder,.components-text-control__input[type=datetime]::-webkit-input-placeholder,.components-text-control__input[type=email]::-webkit-input-placeholder,.components-text-control__input[type=month]::-webkit-input-placeholder,.components-text-control__input[type=number]::-webkit-input-placeholder,.components-text-control__input[type=password]::-webkit-input-placeholder,.components-text-control__input[type=tel]::-webkit-input-placeholder,.components-text-control__input[type=text]::-webkit-input-placeholder,.components-text-control__input[type=time]::-webkit-input-placeholder,.components-text-control__input[type=url]::-webkit-input-placeholder,.components-text-control__input[type=week]::-webkit-input-placeholder{color:#1e1e1e9e}.components-text-control__input::-moz-placeholder,.components-text-control__input[type=color]::-moz-placeholder,.components-text-control__input[type=date]::-moz-placeholder,.components-text-control__input[type=datetime-local]::-moz-placeholder,.components-text-control__input[type=datetime]::-moz-placeholder,.components-text-control__input[type=email]::-moz-placeholder,.components-text-control__input[type=month]::-moz-placeholder,.components-text-control__input[type=number]::-moz-placeholder,.components-text-control__input[type=password]::-moz-placeholder,.components-text-control__input[type=tel]::-moz-placeholder,.components-text-control__input[type=text]::-moz-placeholder,.components-text-control__input[type=time]::-moz-placeholder,.components-text-control__input[type=url]::-moz-placeholder,.components-text-control__input[type=week]::-moz-placeholder{color:#1e1e1e9e}.components-text-control__input:-ms-input-placeholder,.components-text-control__input[type=color]:-ms-input-placeholder,.components-text-control__input[type=date]:-ms-input-placeholder,.components-text-control__input[type=datetime-local]:-ms-input-placeholder,.components-text-control__input[type=datetime]:-ms-input-placeholder,.components-text-control__input[type=email]:-ms-input-placeholder,.components-text-control__input[type=month]:-ms-input-placeholder,.components-text-control__input[type=number]:-ms-input-placeholder,.components-text-control__input[type=password]:-ms-input-placeholder,.components-text-control__input[type=tel]:-ms-input-placeholder,.components-text-control__input[type=text]:-ms-input-placeholder,.components-text-control__input[type=time]:-ms-input-placeholder,.components-text-control__input[type=url]:-ms-input-placeholder,.components-text-control__input[type=week]:-ms-input-placeholder{color:#1e1e1e9e}.components-text-control__input.is-next-40px-default-size,.components-text-control__input[type=color].is-next-40px-default-size,.components-text-control__input[type=date].is-next-40px-default-size,.components-text-control__input[type=datetime-local].is-next-40px-default-size,.components-text-control__input[type=datetime].is-next-40px-default-size,.components-text-control__input[type=email].is-next-40px-default-size,.components-text-control__input[type=month].is-next-40px-default-size,.components-text-control__input[type=number].is-next-40px-default-size,.components-text-control__input[type=password].is-next-40px-default-size,.components-text-control__input[type=tel].is-next-40px-default-size,.components-text-control__input[type=text].is-next-40px-default-size,.components-text-control__input[type=time].is-next-40px-default-size,.components-text-control__input[type=url].is-next-40px-default-size,.components-text-control__input[type=week].is-next-40px-default-size{height:40px;padding-left:12px;padding-right:12px}.components-text-control__input[type=email],.components-text-control__input[type=url]{direction:ltr}.components-tip{color:#757575;display:flex}.components-tip svg{align-self:center;fill:#f0b849;flex-shrink:0;margin-left:16px}.components-tip p{margin:0}.components-toggle-control__label{line-height:16px}.components-toggle-control__label:not(.is-disabled){cursor:pointer}.components-toggle-control__help{display:inline-block;margin-inline-start:40px}.components-accessible-toolbar{border:1px solid #1e1e1e;border-radius:2px;display:inline-flex;flex-shrink:0}.components-accessible-toolbar>.components-toolbar-group:last-child{border-left:none}.components-accessible-toolbar.is-unstyled{border:none}.components-accessible-toolbar.is-unstyled>.components-toolbar-group{border-left:none}.components-accessible-toolbar[aria-orientation=vertical],.components-toolbar[aria-orientation=vertical]{align-items:center;display:flex;flex-direction:column}.components-accessible-toolbar .components-button,.components-toolbar .components-button{height:48px;padding-left:16px;padding-right:16px;position:relative;z-index:1}.components-accessible-toolbar .components-button:focus:not(:disabled),.components-toolbar .components-button:focus:not(:disabled){box-shadow:none;outline:none}.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{border-radius:2px;content:"";display:block;height:32px;left:8px;position:absolute;right:8px;z-index:-1}@media not (prefers-reduced-motion){.components-accessible-toolbar .components-button:before,.components-toolbar .components-button:before{animation:components-button__appear-animation .1s ease;animation-fill-mode:forwards}}.components-accessible-toolbar .components-button svg,.components-toolbar .components-button svg{margin-left:auto;margin-right:auto;position:relative}.components-accessible-toolbar .components-button.is-pressed,.components-accessible-toolbar .components-button.is-pressed:hover,.components-toolbar .components-button.is-pressed,.components-toolbar .components-button.is-pressed:hover{background:#0000}.components-accessible-toolbar .components-button.is-pressed:before,.components-toolbar .components-button.is-pressed:before{background:#1e1e1e}.components-accessible-toolbar .components-button:focus:before,.components-toolbar .components-button:focus:before{box-shadow:inset 0 0 0 1px #fff,0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);outline:2px solid #0000}.components-accessible-toolbar .components-button.has-icon.has-icon,.components-toolbar .components-button.has-icon.has-icon{min-width:48px;padding-left:8px;padding-right:8px}@keyframes components-button__appear-animation{0%{transform:scaleY(0)}to{transform:scaleY(1)}}.components-toolbar__control.components-button{position:relative}.components-toolbar__control.components-button[data-subscript] svg{padding:5px 0 5px 10px}.components-toolbar__control.components-button[data-subscript]:after{bottom:10px;content:attr(data-subscript);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;font-weight:600;left:8px;line-height:12px;position:absolute}.components-toolbar__control.components-button:not(:disabled).is-pressed[data-subscript]:after{color:#fff}.components-toolbar-group{background-color:#fff;border-left:1px solid #1e1e1e;display:inline-flex;flex-shrink:0;flex-wrap:wrap;line-height:0;min-height:48px;padding-left:6px;padding-right:6px}.components-toolbar-group .components-toolbar-group.components-toolbar-group{border-width:0;margin:0}.components-toolbar-group .components-button.components-button,.components-toolbar-group .components-button.has-icon.has-icon{justify-content:center;min-width:36px;padding-left:6px;padding-right:6px}.components-toolbar-group .components-button.components-button svg,.components-toolbar-group .components-button.has-icon.has-icon svg{min-width:24px}.components-toolbar-group .components-button.components-button:before,.components-toolbar-group .components-button.has-icon.has-icon:before{left:2px;right:2px}.components-toolbar{background-color:#fff;border:1px solid #1e1e1e;display:inline-flex;flex-shrink:0;flex-wrap:wrap;margin:0;min-height:48px}.components-toolbar .components-toolbar.components-toolbar{border-width:0;margin:0}div.components-toolbar>div{display:flex;margin:0}div.components-toolbar>div+div.has-left-divider{margin-right:6px;overflow:visible;position:relative}div.components-toolbar>div+div.has-left-divider:before{background-color:#ddd;box-sizing:initial;content:"";display:inline-block;height:20px;position:absolute;right:-3px;top:8px;width:1px}.components-tooltip{background:#000;border-radius:2px;box-shadow:0 1px 2px #0000000d,0 2px 3px #0000000a,0 6px 6px #00000008,0 8px 8px #00000005;color:#f0f0f0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:12px;line-height:1.4;padding:4px 8px;text-align:center;z-index:1000002}.components-tooltip__shortcut{margin-right:8px}