Plugin Directory

Changeset 3103107


Ignore:
Timestamp:
06/15/2024 01:34:20 PM (19 months ago)
Author:
d3395
Message:

The encryptx template function has been revised so that it accepts arguments again, as in previous versions.

Location:
cryptx
Files:
3 edited
5 copied

Legend:

Unmodified
Added
Removed
  • cryptx/tags/3.4.5/classes/CryptX.php

    r3102850 r3103107  
    55class CryptX {
    66
    7     const NOT_FOUND = false;
    8     const MAIL_IDENTIFIER = 'mailto:';
    9     const SUBJECT_IDENTIFIER = "?subject=";
    10     const INDEX_TO_CHECK = 4;
    11     const PATTERN = '/(.*)(">)/i';
    12     const ASCII_VALUES_BLACKLIST = ['32', '34', '39', '60', '62', '63', '92', '94', '96', '127'];
     7    const NOT_FOUND = false;
     8    const MAIL_IDENTIFIER = 'mailto:';
     9    const SUBJECT_IDENTIFIER = "?subject=";
     10    const INDEX_TO_CHECK = 4;
     11    const PATTERN = '/(.*)(">)/i';
     12    const ASCII_VALUES_BLACKLIST = [ '32', '34', '39', '60', '62', '63', '92', '94', '96', '127' ];
    1313
    1414    private static ?CryptX $_instance = null;
    1515    private static array $cryptXOptions = [];
    1616    private static array $defaults = array(
    17         'version' => null,
    18         'at' => ' [at] ',
    19         'dot' => ' [dot] ',
    20         'css_id' => '',
    21         'css_class' => '',
    22         'the_content' => 1,
    23         'the_meta_key' => 1,
    24         'the_excerpt' => 1,
    25         'comment_text' => 1,
    26         'widget_text' => 1,
    27         'java' => 1,
    28         'load_java' => 1,
    29         'opt_linktext' => 0,
    30         'autolink' => 1,
    31         'alt_linktext' => '',
    32         'alt_linkimage' => '',
     17        'version'              => null,
     18        'at'                   => ' [at] ',
     19        'dot'                  => ' [dot] ',
     20        'css_id'               => '',
     21        'css_class'            => '',
     22        'the_content'          => 1,
     23        'the_meta_key'         => 1,
     24        'the_excerpt'          => 1,
     25        'comment_text'         => 1,
     26        'widget_text'          => 1,
     27        'java'                 => 1,
     28        'load_java'            => 1,
     29        'opt_linktext'         => 0,
     30        'autolink'             => 1,
     31        'alt_linktext'         => '',
     32        'alt_linkimage'        => '',
    3333        'http_linkimage_title' => '',
    34         'alt_linkimage_title' => '',
    35         'excludedIDs' => '',
    36         'metaBox' => 1,
    37         'alt_uploadedimage' => '0',
    38         'c2i_font' => null,
    39         'c2i_fontSize' => 10,
    40         'c2i_fontRGB' => '#000000',
    41         'echo' => 1,
    42         'filter' => array('the_content','the_meta_key','the_excerpt','comment_text','widget_text'),
    43         'whiteList' => 'jpeg,jpg,png,gif',
     34        'alt_linkimage_title'  => '',
     35        'excludedIDs'          => '',
     36        'metaBox'              => 1,
     37        'alt_uploadedimage'    => '0',
     38        'c2i_font'             => null,
     39        'c2i_fontSize'         => 10,
     40        'c2i_fontRGB'          => '#000000',
     41        'echo'                 => 1,
     42        'filter'               => array( 'the_content', 'the_meta_key', 'the_excerpt', 'comment_text', 'widget_text' ),
     43        'whiteList'            => 'jpeg,jpg,png,gif',
    4444    );
    4545    private static int $imageCounter = 0;
    46     private function __construct()
    47     {
     46
     47    private function __construct() {
    4848        self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults();
    4949    }
     
    5858     * @return CryptX The instance of the CryptX class.
    5959     */
    60     public static function getInstance(): CryptX
    61     {
    62         if ( ! ( self::$_instance instanceof self) ) {
     60    public static function getInstance(): CryptX {
     61        if ( ! ( self::$_instance instanceof self ) ) {
    6362            self::$_instance = new self();
    6463        }
     64
    6565        return self::$_instance;
    6666    }
    6767
    68     function startCryptX(): void {
    69         if( isset( self::$cryptXOptions['version'] ) && version_compare(CRYPTX_VERSION, self::$cryptXOptions['version']) > 0 ) {
    70             $this->updateCryptXSettings();
    71         }
    72         foreach(self::$cryptXOptions['filter'] as $filter) {
    73             if (@self::$cryptXOptions[$filter]) {
    74                 $this->addPluginFilters($filter);
    75             }
    76         }
    77         add_action( 'activate_' . CRYPTX_BASENAME, [$this, 'installCryptX' ] );
    78         add_action( 'wp_enqueue_scripts', [$this, 'loadJavascriptFiles' ] );
    79         if (@self::$cryptXOptions['metaBox']) {
    80             add_action('admin_menu', [$this, 'metaBox' ]);
    81             add_action('wp_insert_post', [$this, 'addPostIdToExcludedList' ] );
    82             add_action('wp_update_post', [$this, 'addPostIdToExcludedList' ] );
    83         }
    84         add_filter( 'plugin_row_meta', 'rw_cryptx_init_row_meta', 10, 2 );
    85         add_filter( 'init', [$this, 'cryptXtinyUrl' ]);
    86         add_shortcode( 'cryptx', [$this, 'cryptXShortcode']);
    87     }
     68    function startCryptX(): void {
     69        if ( isset( self::$cryptXOptions['version'] ) && version_compare( CRYPTX_VERSION, self::$cryptXOptions['version'] ) > 0 ) {
     70            $this->updateCryptXSettings();
     71        }
     72        foreach ( self::$cryptXOptions['filter'] as $filter ) {
     73            if ( @self::$cryptXOptions[ $filter ] ) {
     74                $this->addPluginFilters( $filter );
     75            }
     76        }
     77        add_action( 'activate_' . CRYPTX_BASENAME, [ $this, 'installCryptX' ] );
     78        add_action( 'wp_enqueue_scripts', [ $this, 'loadJavascriptFiles' ] );
     79        if ( @self::$cryptXOptions['metaBox'] ) {
     80            add_action( 'admin_menu', [ $this, 'metaBox' ] );
     81            add_action( 'wp_insert_post', [ $this, 'addPostIdToExcludedList' ] );
     82            add_action( 'wp_update_post', [ $this, 'addPostIdToExcludedList' ] );
     83        }
     84        add_filter( 'plugin_row_meta', 'rw_cryptx_init_row_meta', 10, 2 );
     85        add_filter( 'init', [ $this, 'cryptXtinyUrl' ] );
     86        add_shortcode( 'cryptx', [ $this, 'cryptXShortcode' ] );
     87    }
    8888
    8989    /**
     
    9595     * @return array The array of default options.
    9696     */
    97     function getCryptXOptionsDefaults(): array
    98     {
    99         $firstFont = $this->getFilesInDirectory( CRYPTX_DIR_PATH . 'fonts', ["ttf"]);
    100         return array_merge(self::$defaults, [ 'version' => CRYPTX_VERSION, 'c2i_font' => $firstFont[0] ]);
     97    function getCryptXOptionsDefaults(): array {
     98        $firstFont = $this->getFilesInDirectory( CRYPTX_DIR_PATH . 'fonts', [ "ttf" ] );
     99
     100        return array_merge( self::$defaults, [ 'version' => CRYPTX_VERSION, 'c2i_font' => $firstFont[0] ] );
    101101    }
    102102
     
    106106     * @return array The cryptX options array with default values.
    107107     */
    108     function loadCryptXOptionsWithDefaults(): array
    109     {
    110         $defaultValues = $this->getCryptXOptionsDefaults();
    111         $currentOptions = get_option('cryptX');
    112         return wp_parse_args($currentOptions, $defaultValues);
     108    function loadCryptXOptionsWithDefaults(): array {
     109        $defaultValues  = $this->getCryptXOptionsDefaults();
     110        $currentOptions = get_option( 'cryptX' );
     111
     112        return wp_parse_args( $currentOptions, $defaultValues );
    113113    }
    114114
     
    120120     * @return void
    121121     */
    122     function saveCryptXOptions( array $saveOptions): void {
    123         update_option( 'cryptX', wp_parse_args( $saveOptions, $this->loadCryptXOptionsWithDefaults() ) );
    124     }
    125 
    126     /**
    127      * Processes the [cryptx] shortcode.
    128      *
    129      * @param array $atts The shortcode attributes.
    130      * @param string $content The content wrapped in the shortcode.
    131      *
    132      * @return string The processed content.
    133      */
    134     function cryptXShortcode( array $atts, string $content): string
    135     {
    136         if (@self::$cryptXOptions['autolink']) {
    137             $content = $this->addLinkToEmailAddresses($content, true);
    138         }
    139 
    140         return $this->encryptAndLinkContent($content);
     122    function saveCryptXOptions( array $saveOptions ): void {
     123        update_option( 'cryptX', wp_parse_args( $saveOptions, $this->loadCryptXOptionsWithDefaults() ) );
     124    }
     125
     126    /**
     127     * Generates a shortcode for encrypting email addresses in search results.
     128     *
     129     * @param array $atts An associative array of attributes for the shortcode.
     130     * @param string $content The content inside the shortcode.
     131     * @param string $tag The shortcode tag.
     132     *
     133     * @return string The encrypted search results content.
     134     */
     135    function cryptXShortcode( array $atts = [], string $content = '', string $tag = '' ): string {
     136        if ( isset( $atts['encoded'] ) && $atts['encoded'] == "true" ) {
     137            foreach ( $atts as $key => $value ) {
     138                $atts[ $key ] = $this->decodeString( $value );
     139            }
     140            unset( $atts['encoded'] );
     141        }
     142
     143        self::$cryptXOptions = shortcode_atts( $this->getCryptXOptionsDefaults(), array_change_key_case( $atts, CASE_LOWER ), $tag );
     144        if ( @self::$cryptXOptions['autolink'] ) {
     145            $content = $this->addLinkToEmailAddresses( $content, true );
     146        }
     147        $content             = $this->encryptAndLinkContent( $content, true );
     148        self::$cryptXOptions = $this->getCryptXOptionsDefaults();
     149
     150        return $content;
    141151    }
    142152
     
    148158     * @return string The encrypted and linked content.
    149159     */
    150     function encryptAndLinkContent( string $content): string {
    151         $content = $this->findEmailAddressesInContent($content, true);
    152         $content = $this->replaceEmailInContent($content, true);
    153         return $content;
    154     }
    155     /**
    156      *  create image from tinyurl
    157      *
    158      *  @return image
    159      */
    160     function cryptXtinyUrl() : void
    161     {
    162         $url                 = $_SERVER['REQUEST_URI'];
     160    function encryptAndLinkContent( string $content, bool $shortcode = false ): string {
     161        $content = $this->findEmailAddressesInContent( $content, $shortcode );
     162
     163        return $this->replaceEmailInContent( $content, $shortcode );
     164    }
     165
     166    /**
     167     * Generates and returns a tiny URL image.
     168     *
     169     * @return void
     170     */
     171    function cryptXtinyUrl(): void {
     172        $url    = $_SERVER['REQUEST_URI'];
    163173        $params = explode( '/', $url );
    164174        if ( count( $params ) > 1 ) {
    165             $tiny_url = $params[count( $params ) -2];
    166             if ( $tiny_url == md5( get_bloginfo('url') ) ) {
    167                 $font = CRYPTX_DIR_PATH . 'fonts/' . self::$cryptXOptions['c2i_font'];
    168                 $msg = $params[count( $params ) -1];
    169                 $size = self::$cryptXOptions['c2i_fontSize'];
    170                 $pad = 1;
     175            $tiny_url = $params[ count( $params ) - 2 ];
     176            if ( $tiny_url == md5( get_bloginfo( 'url' ) ) ) {
     177                $font        = CRYPTX_DIR_PATH . 'fonts/' . self::$cryptXOptions['c2i_font'];
     178                $msg         = $params[ count( $params ) - 1 ];
     179                $size        = self::$cryptXOptions['c2i_fontSize'];
     180                $pad         = 1;
    171181                $transparent = 1;
    172                 $rgb = str_replace("#", "", self::$cryptXOptions['c2i_fontRGB']);
    173                 $red = hexdec(substr($rgb,0,2));
    174                 $grn = hexdec(substr($rgb,2,2));
    175                 $blu = hexdec(substr($rgb,4,2));
    176                 $bg_red = 255 - $red;
    177                 $bg_grn = 255 - $grn;
    178                 $bg_blu = 255 - $blu;
    179                 $width = 0;
    180                 $height = 0;
    181                 $offset_x = 0;
    182                 $offset_y = 0;
    183                 $bounds = array();
    184                 $image = "";
    185                 $bounds = ImageTTFBBox($size, 0, $font, "W");
    186                 $font_height = abs($bounds[7]-$bounds[1]);
    187                 $bounds = ImageTTFBBox($size, 0, $font, $msg);
    188                 $width = abs($bounds[4]-$bounds[6]);
    189                 $height = abs($bounds[7]-$bounds[1]);
    190                 $offset_y = $font_height+abs(($height - $font_height)/2)-1;
    191                 $offset_x = 0;
    192                 $image = imagecreatetruecolor($width+($pad*2),$height+($pad*2));
    193                 imagesavealpha($image, true);
    194                 $foreground = ImageColorAllocate($image, $red, $grn, $blu);
    195                 $background = imagecolorallocatealpha($image, 0, 0, 0, 127);
    196                 imagefill($image, 0, 0, $background);
    197                 ImageTTFText($image, $size, 0, $offset_x+$pad, $offset_y+$pad, $foreground, $font, $msg);
    198                 Header("Content-type: image/png");
    199                 imagePNG($image);
     182                $rgb         = str_replace( "#", "", self::$cryptXOptions['c2i_fontRGB'] );
     183                $red         = hexdec( substr( $rgb, 0, 2 ) );
     184                $grn         = hexdec( substr( $rgb, 2, 2 ) );
     185                $blu         = hexdec( substr( $rgb, 4, 2 ) );
     186                $bg_red      = 255 - $red;
     187                $bg_grn      = 255 - $grn;
     188                $bg_blu      = 255 - $blu;
     189                $width       = 0;
     190                $height      = 0;
     191                $offset_x    = 0;
     192                $offset_y    = 0;
     193                $bounds      = array();
     194                $image       = "";
     195                $bounds      = ImageTTFBBox( $size, 0, $font, "W" );
     196                $font_height = abs( $bounds[7] - $bounds[1] );
     197                $bounds      = ImageTTFBBox( $size, 0, $font, $msg );
     198                $width       = abs( $bounds[4] - $bounds[6] );
     199                $height      = abs( $bounds[7] - $bounds[1] );
     200                $offset_y    = $font_height + abs( ( $height - $font_height ) / 2 ) - 1;
     201                $offset_x    = 0;
     202                $image       = imagecreatetruecolor( $width + ( $pad * 2 ), $height + ( $pad * 2 ) );
     203                imagesavealpha( $image, true );
     204                $foreground = ImageColorAllocate( $image, $red, $grn, $blu );
     205                $background = imagecolorallocatealpha( $image, 0, 0, 0, 127 );
     206                imagefill( $image, 0, 0, $background );
     207                ImageTTFText( $image, $size, 0, round( $offset_x + $pad, 0 ), round( $offset_y + $pad, 0 ), $foreground, $font, $msg );
     208                Header( "Content-type: image/png" );
     209                imagePNG( $image );
    200210                die;
    201211            }
     
    214224     * @return void
    215225     */
    216     function addPluginFilters( string $filterName): void
    217     {
     226    function addPluginFilters( string $filterName ): void {
    218227        global $shortcode_tags;
    219         if ( array_key_exists('autolink', self::$cryptXOptions) && self::$cryptXOptions['autolink']) {
    220             $this->addAutoLinkFilters($filterName);
    221             if (!empty($shortcode_tags)) {
    222                 $this->addAutoLinkFilters($filterName, 11);
     228        if ( array_key_exists( 'autolink', self::$cryptXOptions ) && self::$cryptXOptions['autolink'] ) {
     229            $this->addAutoLinkFilters( $filterName );
     230            if ( ! empty( $shortcode_tags ) ) {
     231                $this->addAutoLinkFilters( $filterName, 11 );
    223232                //add_filter($filterName, [$this,'autolink'], 11);
    224233            }
    225234        }
    226         $this->addOtherFilters($filterName);
     235        $this->addOtherFilters( $filterName );
    227236    }
    228237
     
    236245     * @return void
    237246     */
    238     function addAutoLinkFilters( string $filterName, $prio = 5): void
    239     {
    240         add_filter($filterName, [$this, 'addLinkToEmailAddresses' ], $prio);
     247    function addAutoLinkFilters( string $filterName, $prio = 5 ): void {
     248        add_filter( $filterName, [ $this, 'addLinkToEmailAddresses' ], $prio );
    241249    }
    242250
     
    252260     * @return void
    253261     */
    254     function addOtherFilters( string $filterName): void
    255     {
    256         add_filter($filterName, [$this, 'findEmailAddressesInContent' ], 12);
    257         add_filter($filterName, [$this,'replaceEmailInContent'], 13);
     262    function addOtherFilters( string $filterName ): void {
     263        add_filter( $filterName, [ $this, 'findEmailAddressesInContent' ], 12 );
     264        add_filter( $filterName, [ $this, 'replaceEmailInContent' ], 13 );
    258265    }
    259266
     
    265272     * @return bool Returns true if the ID is excluded, false otherwise.
    266273     */
    267     function isIdExcluded( int $ID): bool
    268     {
    269         $excludedIds = explode(",", self::$cryptXOptions['excludedIDs']);
    270         return in_array($ID, $excludedIds);
     274    function isIdExcluded( int $ID ): bool {
     275        $excludedIds = explode( ",", self::$cryptXOptions['excludedIDs'] );
     276
     277        return in_array( $ID, $excludedIds );
    271278    }
    272279
     
    279286     * @param string $content The
    280287     */
    281     function replaceEmailInContent( string $content, bool $isShortcode=false): string {
     288    function replaceEmailInContent( string $content, bool $isShortcode = false ): string {
    282289        global $post;
    283         $postId = (is_object($post))? $post->ID : -1;
    284         if ( !$this->isIdExcluded($postId) || $isShortcode ) {
    285             $content = $this->replaceEmailWithLinkText($content);
    286         }
     290        $postId = ( is_object( $post ) ) ? $post->ID : - 1;
     291        if ( ! $this->isIdExcluded( $postId ) || $isShortcode ) {
     292            $content = $this->replaceEmailWithLinkText( $content );
     293        }
     294
    287295        return $content;
    288296    }
     
    295303     * @return string The content with email addresses replaced with link text.
    296304     */
    297     function replaceEmailWithLinkText( string $content): string
    298     {
     305    function replaceEmailWithLinkText( string $content ): string {
    299306        $emailPattern = "/([_a-zA-Z0-9-+]+(\.[_a-zA-Z0-9-+]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,}))/i";
    300         return preg_replace_callback($emailPattern, [$this,'encodeEmailToLinkText'], $content );
     307
     308        return preg_replace_callback( $emailPattern, [ $this, 'encodeEmailToLinkText' ], $content );
    301309    }
    302310
     
    308316     * @return string The encoded link text.
    309317     */
    310     function encodeEmailToLinkText( array $Match): string {
    311         if($this->in_white_list($Match)) return $Match[1];
    312         switch (self::$cryptXOptions['opt_linktext']) {
     318    function encodeEmailToLinkText( array $Match ): string {
     319        if ( $this->inWhiteList( $Match ) ) {
     320            return $Match[1];
     321        }
     322        switch ( self::$cryptXOptions['opt_linktext'] ) {
    313323            case 1:
    314324                $text = $this->getLinkText();
     
    319329            case 3:
    320330                $img_url = wp_get_attachment_url( self::$cryptXOptions['alt_uploadedimage'] );
    321                 $text = $this->getUploadedImage($img_url);
    322                 self::$imageCounter++;
     331                $text    = $this->getUploadedImage( $img_url );
     332                self::$imageCounter ++;
    323333                break;
    324334            case 4:
    325                 $text = antispambot($Match[1]);
     335                $text = antispambot( $Match[1] );
    326336                break;
    327337            case 5:
    328                 $text = $this->getImageFromText($Match);
    329                 self::$imageCounter++;
     338                $text = $this->getImageFromText( $Match );
     339                self::$imageCounter ++;
    330340                break;
    331341            default:
    332                 $text = $this->getDefaultLinkText($Match);
     342                $text = $this->getDefaultLinkText( $Match );
    333343        }
    334344
     
    343353     * @return bool True if the match is in the whitelist, false otherwise.
    344354     */
    345     function in_white_list( array $Match): bool
    346     {
    347         $whiteList = array_filter(array_map('trim', explode(",", self::$cryptXOptions['whiteList'])));
    348         $tmp = explode(".", $Match[0]);
    349         return in_array(end($tmp), $whiteList);
     355    function inWhiteList( array $Match ): bool {
     356        $whiteList = array_filter( array_map( 'trim', explode( ",", self::$cryptXOptions['whiteList'] ) ) );
     357        $tmp       = explode( ".", $Match[0] );
     358
     359        return in_array( end( $tmp ), $whiteList );
    350360    }
    351361
     
    364374     * @return string The HTML image tag
    365375     */
    366     function getLinkImage(): string
    367     {
    368         return "<img src=\"" . self::$cryptXOptions['alt_linkimage'] . "\" class=\"cryptxImage\" alt=\"" . self::$cryptXOptions['alt_linkimage_title'] . "\" title=\"" . antispambot(self::$cryptXOptions['alt_linkimage_title']) . "\" />";
     376    function getLinkImage(): string {
     377        return "<img src=\"" . self::$cryptXOptions['alt_linkimage'] . "\" class=\"cryptxImage\" alt=\"" . self::$cryptXOptions['alt_linkimage_title'] . "\" title=\"" . antispambot( self::$cryptXOptions['alt_linkimage_title'] ) . "\" />";
    369378    }
    370379
     
    376385     * @return string The HTML tag for the image.
    377386     */
    378     function getUploadedImage( string $img_url): string
    379     {
    380         return "<img src=\"" . $img_url . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . self::$cryptXOptions['http_linkimage_title'] . " title=\"" . antispambot( self::$cryptXOptions['http_linkimage_title']) . "\" />";
     387    function getUploadedImage( string $img_url ): string {
     388        return "<img src=\"" . $img_url . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . self::$cryptXOptions['http_linkimage_title'] . " title=\"" . antispambot( self::$cryptXOptions['http_linkimage_title'] ) . "\" />";
    381389    }
    382390
     
    388396     * @return string Returns the HTML image element.
    389397     */
    390     function getImageFromText( array $Match): string
    391     {
    392         return "<img src=\"" . get_bloginfo('url') . "/" . md5( get_bloginfo('url') ) . "/" . antispambot($Match[1]) . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . antispambot($Match[1]) . "\" title=\"" . antispambot($Match[1]) . "\" />";
     398    function getImageFromText( array $Match ): string {
     399        return "<img src=\"" . get_bloginfo( 'url' ) . "/" . md5( get_bloginfo( 'url' ) ) . "/" . antispambot( $Match[1] ) . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . antispambot( $Match[1] ) . "\" title=\"" . antispambot( $Match[1] ) . "\" />";
    393400    }
    394401
     
    404411     *                     for each element.
    405412     */
    406     function getDefaultLinkText( array $Match): string
    407     {
    408         $text = str_replace("@", self::$cryptXOptions['at'], $Match[1]);
    409         return str_replace(".", self::$cryptXOptions['dot'], $text);
     413    function getDefaultLinkText( array $Match ): string {
     414        $text = str_replace( "@", self::$cryptXOptions['at'], $Match[1] );
     415
     416        return str_replace( ".", self::$cryptXOptions['dot'], $text );
    410417    }
    411418
     
    419426     * @return array An array of file names that match the filter.
    420427     */
    421     function getFilesInDirectory( string $path, array $filter): array
    422     {
    423         $directoryHandle = opendir($path);
     428    function getFilesInDirectory( string $path, array $filter ): array {
     429        $directoryHandle  = opendir( $path );
    424430        $directoryContent = array();
    425         while ($file = readdir($directoryHandle)) {
    426             $fileExtension = substr(strtolower($file), -3);
    427             if (in_array($fileExtension, $filter)) {
     431        while ( $file = readdir( $directoryHandle ) ) {
     432            $fileExtension = substr( strtolower( $file ), - 3 );
     433            if ( in_array( $fileExtension, $filter ) ) {
    428434                $directoryContent[] = $file;
    429435            }
    430436        }
     437
    431438        return $directoryContent;
    432439    }
     
    440447     * @return string|null The content with encrypted email addresses, or null if $content is null.
    441448     */
    442     function findEmailAddressesInContent( ?string $content, bool $shortcode = false): ?string
    443     {
    444         global $post;
    445 
    446         if ($content === null) return null;
    447 
    448         $postId = (is_object($post))? $post->ID : -1;
    449 
    450         $isIdExcluded = $this->isIdExcluded($postId);
    451         $mailtoRegex = '/<a (.*?)(href=("|\')mailto:(.*?)("|\')(.*?)|)>\s*(.*?)\s*<\/a>/i';
    452 
    453         if ((!$isIdExcluded || $shortcode !== null)) {
    454             $content = preg_replace_callback($mailtoRegex, [$this, 'encryptEmailAddress' ], $content);
     449    function findEmailAddressesInContent( ?string $content, bool $shortcode = false ): ?string {
     450        global $post;
     451
     452        if ( $content === null ) {
     453            return null;
     454        }
     455
     456        $postId = ( is_object( $post ) ) ? $post->ID : - 1;
     457
     458        $isIdExcluded = $this->isIdExcluded( $postId );
     459        $mailtoRegex  = '/<a (.*?)(href=("|\')mailto:(.*?)("|\')(.*?)|)>\s*(.*?)\s*<\/a>/i';
     460
     461        if ( ( ! $isIdExcluded || $shortcode !== null ) ) {
     462            $content = preg_replace_callback( $mailtoRegex, [ $this, 'encryptEmailAddress' ], $content );
    455463        }
    456464
     
    465473     * @return string The search results with encrypted email addresses.
    466474     */
    467     function encryptEmailAddress( array $searchResults): string
    468     {
     475    function encryptEmailAddress( array $searchResults ): string {
    469476        $originalValue = $searchResults[0];
    470477
    471         if(strpos($searchResults[self::INDEX_TO_CHECK], '@') === self::NOT_FOUND) {
     478        if ( strpos( $searchResults[ self::INDEX_TO_CHECK ], '@' ) === self::NOT_FOUND ) {
    472479            return $originalValue;
    473480        }
    474481
    475         $mailReference = self::MAIL_IDENTIFIER . $searchResults[self::INDEX_TO_CHECK];
     482        $mailReference = self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK ];
    476483
    477484        if ( str_starts_with( $searchResults[ self::INDEX_TO_CHECK ], self::SUBJECT_IDENTIFIER ) ) {
     
    480487
    481488        $return = $originalValue;
    482         if (!empty(self::$cryptXOptions['java'])) {
    483             $javaHandler="javascript:DeCryptX('" . $this->generateHashFromString($searchResults[self::INDEX_TO_CHECK]) . "')";
    484             $return = str_replace(self::MAIL_IDENTIFIER.$searchResults[self::INDEX_TO_CHECK], $javaHandler, $originalValue);
    485         }
    486 
    487         $return = str_replace($mailReference, antispambot($mailReference), $return);
    488 
    489         if(!empty(self::$cryptXOptions['css_id'])) {
    490             $return = preg_replace(self::PATTERN, '$1" id="'.self::$cryptXOptions['css_id'] . '">', $return );
    491         }
    492 
    493         if(!empty(self::$cryptXOptions['css_class'])) {
    494             $return = preg_replace(self::PATTERN, '$1" class="'.self::$cryptXOptions['css_class'] . '">', $return );
     489        if ( ! empty( self::$cryptXOptions['java'] ) ) {
     490            $javaHandler = "javascript:DeCryptX('" . $this->generateHashFromString( $searchResults[ self::INDEX_TO_CHECK ] ) . "')";
     491            $return      = str_replace( self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK ], $javaHandler, $originalValue );
     492        }
     493
     494        $return = str_replace( $mailReference, antispambot( $mailReference ), $return );
     495
     496        if ( ! empty( self::$cryptXOptions['css_id'] ) ) {
     497            $return = preg_replace( self::PATTERN, '$1" id="' . self::$cryptXOptions['css_id'] . '">', $return );
     498        }
     499
     500        if ( ! empty( self::$cryptXOptions['css_class'] ) ) {
     501            $return = preg_replace( self::PATTERN, '$1" class="' . self::$cryptXOptions['css_class'] . '">', $return );
    495502        }
    496503
     
    506513     * @return string The generated hash string.
    507514     */
    508     function generateHashFromString( string $inputString): string
    509     {
    510         $inputString = str_replace("&", "&", $inputString);
    511         $crypt = '';
    512 
    513         for ($i = 0; $i < strlen($inputString); $i++) {
     515    function generateHashFromString( string $inputString ): string {
     516        $inputString = str_replace( "&", "&", $inputString );
     517        $crypt       = '';
     518
     519        for ( $i = 0; $i < strlen( $inputString ); $i ++ ) {
    514520            do {
    515                 $salt = mt_rand(0, 3);
    516                 $asciiValue = ord(substr($inputString, $i)) + $salt;
    517                 if (8364 <= $asciiValue) {
     521                $salt       = mt_rand( 0, 3 );
     522                $asciiValue = ord( substr( $inputString, $i ) ) + $salt;
     523                if ( 8364 <= $asciiValue ) {
    518524                    $asciiValue = 128;
    519525                }
    520             } while (in_array($asciiValue, self::ASCII_VALUES_BLACKLIST));
    521 
    522             $crypt .= $salt . chr($asciiValue);
    523         }
     526            } while ( in_array( $asciiValue, self::ASCII_VALUES_BLACKLIST ) );
     527
     528            $crypt .= $salt . chr( $asciiValue );
     529        }
     530
    524531        return $crypt;
    525532    }
     
    535542     * @return string The content with emails auto-linked.
    536543     */
    537     function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string
    538     {
     544    function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string {
    539545        global $post;
    540546        $postID = is_object( $post ) ? $post->ID : - 1;
     
    575581    function installCryptX(): void {
    576582        global $wpdb;
    577         self::$cryptXOptions['admin_notices_deprecated'] =true;
    578         if ( self::$cryptXOptions['excludedIDs'] == "") {
    579             $tmp = array();
    580             $excludes = $wpdb->get_results("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff' AND meta_value = 'true'");
    581             if(count($excludes) > 0) {
    582                 foreach ($excludes as $exclude) {
     583        self::$cryptXOptions['admin_notices_deprecated'] = true;
     584        if ( self::$cryptXOptions['excludedIDs'] == "" ) {
     585            $tmp      = array();
     586            $excludes = $wpdb->get_results( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff' AND meta_value = 'true'" );
     587            if ( count( $excludes ) > 0 ) {
     588                foreach ( $excludes as $exclude ) {
    583589                    $tmp[] = $exclude->post_id;
    584590                }
    585                 sort($tmp);
    586                 self::$cryptXOptions['excludedIDs'] = implode(",", $tmp);
    587                 update_option( 'cryptX', self::$cryptXOptions);
     591                sort( $tmp );
     592                self::$cryptXOptions['excludedIDs'] = implode( ",", $tmp );
     593                update_option( 'cryptX', self::$cryptXOptions );
    588594                self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); // reread Options
    589                 $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff'");
    590             }
    591         }
    592         if (empty(self::$cryptXOptions['c2i_font'])) {
     595                $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff'" );
     596            }
     597        }
     598        if ( empty( self::$cryptXOptions['c2i_font'] ) ) {
    593599            self::$cryptXOptions['c2i_font'] = CRYPTX_DIR_PATH . 'fonts/' . $firstFont[0];
    594600        }
    595         if (empty(self::$cryptXOptions['c2i_fontSize'])) {
     601        if ( empty( self::$cryptXOptions['c2i_fontSize'] ) ) {
    596602            self::$cryptXOptions['c2i_fontSize'] = 10;
    597603        }
    598         if (empty(self::$cryptXOptions['c2i_fontRGB'])) {
     604        if ( empty( self::$cryptXOptions['c2i_fontRGB'] ) ) {
    599605            self::$cryptXOptions['c2i_fontRGB'] = '000000';
    600606        }
    601         update_option( 'cryptX', self::$cryptXOptions);
     607        update_option( 'cryptX', self::$cryptXOptions );
    602608        self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); // reread Options
    603609    }
    604610
    605     function addHooksHelper($function_name, $hook_name): void {
    606         if ( function_exists($function_name) ) {
    607             call_user_func($function_name, 'cryptx', 'CryptX', [$this, 'metaCheckbox' ], $hook_name);
     611    function addHooksHelper( $function_name, $hook_name ): void {
     612        if ( function_exists( $function_name ) ) {
     613            call_user_func( $function_name, 'cryptx', 'CryptX', [ $this, 'metaCheckbox' ], $hook_name );
    608614        } else {
    609             add_action("dbx_{$hook_name}_sidebar", [$this, 'metaOptionFieldset' ]);
     615            add_action( "dbx_{$hook_name}_sidebar", [ $this, 'metaOptionFieldset' ] );
    610616        }
    611617    }
    612618
    613619    function metaBox(): void {
    614         $this->addHooksHelper('add_meta_box', 'post');
    615         $this->addHooksHelper('add_meta_box', 'page');
     620        $this->addHooksHelper( 'add_meta_box', 'post' );
     621        $this->addHooksHelper( 'add_meta_box', 'page' );
    616622    }
    617623
     
    622628     * functionality for the current post or page. If the current post or page ID is excluded
    623629     **/
    624     function metaCheckbox(): void
    625     {
     630    function metaCheckbox(): void {
    626631        global $post;
    627632        ?>
    628         <label><input type="checkbox" name="disable_cryptx_pageid" <?php if ($this->isIdExcluded($post->ID)) { echo 'checked="checked"'; } ?>/>
    629         Disable CryptX for this post/page</label>
     633        <label><input type="checkbox" name="disable_cryptx_pageid" <?php if ( $this->isIdExcluded( $post->ID ) ) {
     634                echo 'checked="checked"';
     635            } ?>/>
     636            Disable CryptX for this post/page</label>
    630637        <?php
    631638    }
     
    637644     * @return void
    638645     */
    639     function metaOptionFieldset(): void
    640     {
     646    function metaOptionFieldset(): void {
    641647        global $post;
    642         if ( current_user_can('edit_posts') ) { ?>
    643             <fieldset id="cryptxoption" class="dbx-box">
    644                 <h3 class="dbx-handle">CryptX</h3>
    645                 <div class="dbx-content">
    646                     <label><input type="checkbox" name="disable_cryptx_pageid" <?php if ($this->isIdExcluded($post->ID)) { echo 'checked="checked"'; } ?>/> Disable CryptX for this post/page</label>
    647                 </div>
    648             </fieldset>
     648        if ( current_user_can( 'edit_posts' ) ) { ?>
     649            <fieldset id="cryptxoption" class="dbx-box">
     650                <h3 class="dbx-handle">CryptX</h3>
     651                <div class="dbx-content">
     652                    <label><input type="checkbox"
     653                                  name="disable_cryptx_pageid" <?php if ( $this->isIdExcluded( $post->ID ) ) {
     654                            echo 'checked="checked"';
     655                        } ?>/> Disable CryptX for this post/page</label>
     656                </div>
     657            </fieldset>
    649658            <?php
    650659        }
     
    658667     * @return void
    659668     */
    660     function addPostIdToExcludedList( int $postId): void {
    661         $postId                             = wp_is_post_revision($postId) ?: $postId;
    662         $excludedIds                        = $this->updateExcludedIdsList(self::$cryptXOptions['excludedIDs'], $postId);
    663         self::$cryptXOptions['excludedIDs'] = implode(",", array_filter($excludedIds));
    664         update_option('cryptX', self::$cryptXOptions);
     669    function addPostIdToExcludedList( int $postId ): void {
     670        $postId                             = wp_is_post_revision( $postId ) ?: $postId;
     671        $excludedIds                        = $this->updateExcludedIdsList( self::$cryptXOptions['excludedIDs'], $postId );
     672        self::$cryptXOptions['excludedIDs'] = implode( ",", array_filter( $excludedIds ) );
     673        update_option( 'cryptX', self::$cryptXOptions );
    665674    }
    666675
     
    673682     * @return array The updated excluded IDs list as an array, with the ID removed if it existed and added if necessary.
    674683     */
    675     function updateExcludedIdsList(string $excludedIds, int $postId): array {
    676         $excludedIdsArray = explode(",", $excludedIds);
    677         $excludedIdsArray = $this->removePostIdFromExcludedIds($excludedIdsArray, $postId);
    678         $excludedIdsArray = $this->addPostIdToExcludedIdsIfNecessary($excludedIdsArray, $postId);
    679         return $this->makeExcludedIdsUniqueAndSorted($excludedIdsArray);
     684    function updateExcludedIdsList( string $excludedIds, int $postId ): array {
     685        $excludedIdsArray = explode( ",", $excludedIds );
     686        $excludedIdsArray = $this->removePostIdFromExcludedIds( $excludedIdsArray, $postId );
     687        $excludedIdsArray = $this->addPostIdToExcludedIdsIfNecessary( $excludedIdsArray, $postId );
     688
     689        return $this->makeExcludedIdsUniqueAndSorted( $excludedIdsArray );
    680690    }
    681691
     
    688698     * @return array The updated array of excluded IDs without the specified post ID.
    689699     */
    690     function removePostIdFromExcludedIds(array $excludedIds, int $postId): array {
    691         foreach($excludedIds as $key => $id) {
    692             if($id == $postId) {
    693                 unset($excludedIds[$key]);
     700    function removePostIdFromExcludedIds( array $excludedIds, int $postId ): array {
     701        foreach ( $excludedIds as $key => $id ) {
     702            if ( $id == $postId ) {
     703                unset( $excludedIds[ $key ] );
    694704                break;
    695705            }
    696706        }
     707
    697708        return $excludedIds;
    698709    }
     
    706717     * @return array The updated array of excluded IDs.
    707718     */
    708     function addPostIdToExcludedIdsIfNecessary(array $excludedIds, int $postId): array {
    709         if (isset($_POST['disable_cryptx_pageid'])) {
     719    function addPostIdToExcludedIdsIfNecessary( array $excludedIds, int $postId ): array {
     720        if ( isset( $_POST['disable_cryptx_pageid'] ) ) {
    710721            $excludedIds[] = $postId;
    711722        }
     723
    712724        return $excludedIds;
    713725    }
     
    720732     * @return array The array of excluded IDs with duplicate values removed and sorted in ascending order.
    721733     */
    722     function makeExcludedIdsUniqueAndSorted(array $excludedIds): array {
    723         $excludedIds = array_unique($excludedIds);
    724         sort($excludedIds);
     734    function makeExcludedIdsUniqueAndSorted( array $excludedIds ): array {
     735        $excludedIds = array_unique( $excludedIds );
     736        sort( $excludedIds );
     737
    725738        return $excludedIds;
    726739    }
     
    734747     * @return void
    735748     */
    736     function showMessage($message, $errormsg = false): void {
    737         if ($errormsg) {
     749    function showMessage( $message, $errormsg = false ): void {
     750        if ( $errormsg ) {
    738751            echo '<div id="message" class="error">';
    739         }
    740         else {
     752        } else {
    741753            echo '<div id="message" class="updated fade">';
    742754        }
     
    751763     */
    752764    function getDomain(): string {
    753         return $this->trimSlashFromDomain($this->removeProtocolFromUrl($this->getSiteUrl()));
     765        return $this->trimSlashFromDomain( $this->removeProtocolFromUrl( $this->getSiteUrl() ) );
    754766    }
    755767
     
    770782     * @return string The URL string without the protocol.
    771783     */
    772     function removeProtocolFromUrl(string $url): string
    773     {
     784    function removeProtocolFromUrl( string $url ): string {
    774785        return preg_replace( '|https?://|', '', $url );
    775786    }
     
    782793     * @return string The domain with the trailing slash removed.
    783794     */
    784     function trimSlashFromDomain(string $domain): string
    785     {
     795    function trimSlashFromDomain( string $domain ): string {
    786796        if ( $slashPosition = strpos( $domain, '/' ) ) {
    787797            $domain = substr( $domain, 0, $slashPosition );
    788798        }
     799
    789800        return $domain;
    790801    }
     
    797808    function loadJavascriptFiles(): void {
    798809        wp_enqueue_script( 'cryptx-js', CRYPTX_DIR_URL . 'js/cryptx.min.js', false, false, self::$cryptXOptions['load_java'] );
    799         wp_enqueue_style( 'cryptx-styles', CRYPTX_DIR_URL . 'css/cryptx.css');
     810        wp_enqueue_style( 'cryptx-styles', CRYPTX_DIR_URL . 'css/cryptx.css' );
    800811    }
    801812
     
    810821     */
    811822    function updateCryptXSettings(): void {
    812         self::$cryptXOptions = get_option('cryptX');
    813         if( isset( self::$cryptXOptions['version'] ) && version_compare(CRYPTX_VERSION, self::$cryptXOptions['version']) > 0 ) {
    814             if( isset(self::$cryptXOptions['version']) ) unset(self::$cryptXOptions['version']);
    815             if( isset(self::$cryptXOptions['c2i_font']) ) unset(self::$cryptXOptions['c2i_font']);
    816             if( isset(self::$cryptXOptions['c2i_fontRGB']) ) self::$cryptXOptions['c2i_fontRGB'] = "#" . self::$cryptXOptions['c2i_fontRGB'];
    817             if( isset(self::$cryptXOptions['alt_uploadedimage']) && !is_int(self::$cryptXOptions['alt_uploadedimage'])) {
    818                 unset(self::$cryptXOptions['alt_uploadedimage']);
    819                 if( self::$cryptXOptions['opt_linktext'] == 3 ) unset(self::$cryptXOptions['opt_linktext']);
     823        self::$cryptXOptions = get_option( 'cryptX' );
     824        if ( isset( self::$cryptXOptions['version'] ) && version_compare( CRYPTX_VERSION, self::$cryptXOptions['version'] ) > 0 ) {
     825            if ( isset( self::$cryptXOptions['version'] ) ) {
     826                unset( self::$cryptXOptions['version'] );
     827            }
     828            if ( isset( self::$cryptXOptions['c2i_font'] ) ) {
     829                unset( self::$cryptXOptions['c2i_font'] );
     830            }
     831            if ( isset( self::$cryptXOptions['c2i_fontRGB'] ) ) {
     832                self::$cryptXOptions['c2i_fontRGB'] = "#" . self::$cryptXOptions['c2i_fontRGB'];
     833            }
     834            if ( isset( self::$cryptXOptions['alt_uploadedimage'] ) && ! is_int( self::$cryptXOptions['alt_uploadedimage'] ) ) {
     835                unset( self::$cryptXOptions['alt_uploadedimage'] );
     836                if ( self::$cryptXOptions['opt_linktext'] == 3 ) {
     837                    unset( self::$cryptXOptions['opt_linktext'] );
     838                }
    820839            }
    821840            self::$cryptXOptions = wp_parse_args( self::$cryptXOptions, $this->getCryptXOptionsDefaults() );
    822             update_option( 'cryptX', self::$cryptXOptions);
    823         }
     841            update_option( 'cryptX', self::$cryptXOptions );
     842        }
     843    }
     844
     845    /**
     846     * Encodes a string by replacing special characters with their corresponding HTML entities.
     847     *
     848     * @param string|null $str The string to be encoded.
     849     *
     850     * @return string The encoded string, or an array of encoded strings if an array was passed.
     851     */
     852    function encodeString( ?string $str ): string {
     853        $str     = htmlentities( $str, ENT_QUOTES, 'UTF-8' );
     854        $special = array(
     855            '[' => '&#91;',
     856            ']' => '&#93;',
     857        );
     858
     859        return str_replace( array_keys( $special ), array_values( $special ), $str );
     860    }
     861
     862    /**
     863     * Decodes a string that has been HTML entity encoded.
     864     *
     865     * @param string|null $str The string to decode. If null, an empty string is returned.
     866     *
     867     * @return string The decoded string.
     868     */
     869    function decodeString( ?string $str ): string {
     870        return html_entity_decode( $str, ENT_QUOTES, 'UTF-8' );
     871    }
     872
     873    function convertArrayToArgumentString( array $args = [] ): string {
     874        $string = "";
     875        if ( ! empty( $args ) ) {
     876            foreach ( $args as $key => $value ) {
     877                $string .= sprintf( " %s=\"%s\"", $key, $this->encodeString( $value ) );
     878            }
     879            $string .= " encoded=\"true\"";
     880        }
     881
     882        return $string;
    824883    }
    825884}
  • cryptx/tags/3.4.5/cryptx.php

    r3102850 r3103107  
    44 * Plugin URI: http://weber-nrw.de/wordpress/cryptx/
    55 * Description: No more SPAM by spiders scanning you site for email addresses. With CryptX you can hide all your email addresses, with and without a mailto-link, by converting them using javascript or UNICODE.
    6  * Version: 3.4.4
     6 * Version: 3.4.5
    77 * Requires at least: 6.0
    88 * Author: Ralf Weber
     
    4242 * @return string The encrypted content wrapped in the Cryptx shortcode.
    4343 */
    44 function encryptx( ?string $content, string $args = "" ): string {
    45     return do_shortcode( '[cryptx]' . $content . '[/cryptx]' );
     44function encryptx( ?string $content, ?array $args ): string {
     45    $CryptX_instance = Cryptx\CryptX::getInstance();
     46    return do_shortcode( '[cryptx'. $CryptX_instance->convertArrayToArgumentString( $args ).']' . $content . '[/cryptx]' );
    4647}
  • cryptx/tags/3.4.5/readme.txt

    r3102850 r3103107  
    55Requires at least: 6.0
    66Tested up to: 6.5
    7 Stable tag: 3.4.4
     7Stable tag: 3.4.5
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    2222
    2323== Changelog ==
     24= 3.4.5 =
     25* The "encryptx" template function has been revised so that it accepts arguments again, as in previous versions.
    2426= 3.4.4 =
    2527* changed type hinting of an argument to be string or null on some methods
  • cryptx/trunk/classes/CryptX.php

    r3102850 r3103107  
    55class CryptX {
    66
    7     const NOT_FOUND = false;
    8     const MAIL_IDENTIFIER = 'mailto:';
    9     const SUBJECT_IDENTIFIER = "?subject=";
    10     const INDEX_TO_CHECK = 4;
    11     const PATTERN = '/(.*)(">)/i';
    12     const ASCII_VALUES_BLACKLIST = ['32', '34', '39', '60', '62', '63', '92', '94', '96', '127'];
     7    const NOT_FOUND = false;
     8    const MAIL_IDENTIFIER = 'mailto:';
     9    const SUBJECT_IDENTIFIER = "?subject=";
     10    const INDEX_TO_CHECK = 4;
     11    const PATTERN = '/(.*)(">)/i';
     12    const ASCII_VALUES_BLACKLIST = [ '32', '34', '39', '60', '62', '63', '92', '94', '96', '127' ];
    1313
    1414    private static ?CryptX $_instance = null;
    1515    private static array $cryptXOptions = [];
    1616    private static array $defaults = array(
    17         'version' => null,
    18         'at' => ' [at] ',
    19         'dot' => ' [dot] ',
    20         'css_id' => '',
    21         'css_class' => '',
    22         'the_content' => 1,
    23         'the_meta_key' => 1,
    24         'the_excerpt' => 1,
    25         'comment_text' => 1,
    26         'widget_text' => 1,
    27         'java' => 1,
    28         'load_java' => 1,
    29         'opt_linktext' => 0,
    30         'autolink' => 1,
    31         'alt_linktext' => '',
    32         'alt_linkimage' => '',
     17        'version'              => null,
     18        'at'                   => ' [at] ',
     19        'dot'                  => ' [dot] ',
     20        'css_id'               => '',
     21        'css_class'            => '',
     22        'the_content'          => 1,
     23        'the_meta_key'         => 1,
     24        'the_excerpt'          => 1,
     25        'comment_text'         => 1,
     26        'widget_text'          => 1,
     27        'java'                 => 1,
     28        'load_java'            => 1,
     29        'opt_linktext'         => 0,
     30        'autolink'             => 1,
     31        'alt_linktext'         => '',
     32        'alt_linkimage'        => '',
    3333        'http_linkimage_title' => '',
    34         'alt_linkimage_title' => '',
    35         'excludedIDs' => '',
    36         'metaBox' => 1,
    37         'alt_uploadedimage' => '0',
    38         'c2i_font' => null,
    39         'c2i_fontSize' => 10,
    40         'c2i_fontRGB' => '#000000',
    41         'echo' => 1,
    42         'filter' => array('the_content','the_meta_key','the_excerpt','comment_text','widget_text'),
    43         'whiteList' => 'jpeg,jpg,png,gif',
     34        'alt_linkimage_title'  => '',
     35        'excludedIDs'          => '',
     36        'metaBox'              => 1,
     37        'alt_uploadedimage'    => '0',
     38        'c2i_font'             => null,
     39        'c2i_fontSize'         => 10,
     40        'c2i_fontRGB'          => '#000000',
     41        'echo'                 => 1,
     42        'filter'               => array( 'the_content', 'the_meta_key', 'the_excerpt', 'comment_text', 'widget_text' ),
     43        'whiteList'            => 'jpeg,jpg,png,gif',
    4444    );
    4545    private static int $imageCounter = 0;
    46     private function __construct()
    47     {
     46
     47    private function __construct() {
    4848        self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults();
    4949    }
     
    5858     * @return CryptX The instance of the CryptX class.
    5959     */
    60     public static function getInstance(): CryptX
    61     {
    62         if ( ! ( self::$_instance instanceof self) ) {
     60    public static function getInstance(): CryptX {
     61        if ( ! ( self::$_instance instanceof self ) ) {
    6362            self::$_instance = new self();
    6463        }
     64
    6565        return self::$_instance;
    6666    }
    6767
    68     function startCryptX(): void {
    69         if( isset( self::$cryptXOptions['version'] ) && version_compare(CRYPTX_VERSION, self::$cryptXOptions['version']) > 0 ) {
    70             $this->updateCryptXSettings();
    71         }
    72         foreach(self::$cryptXOptions['filter'] as $filter) {
    73             if (@self::$cryptXOptions[$filter]) {
    74                 $this->addPluginFilters($filter);
    75             }
    76         }
    77         add_action( 'activate_' . CRYPTX_BASENAME, [$this, 'installCryptX' ] );
    78         add_action( 'wp_enqueue_scripts', [$this, 'loadJavascriptFiles' ] );
    79         if (@self::$cryptXOptions['metaBox']) {
    80             add_action('admin_menu', [$this, 'metaBox' ]);
    81             add_action('wp_insert_post', [$this, 'addPostIdToExcludedList' ] );
    82             add_action('wp_update_post', [$this, 'addPostIdToExcludedList' ] );
    83         }
    84         add_filter( 'plugin_row_meta', 'rw_cryptx_init_row_meta', 10, 2 );
    85         add_filter( 'init', [$this, 'cryptXtinyUrl' ]);
    86         add_shortcode( 'cryptx', [$this, 'cryptXShortcode']);
    87     }
     68    function startCryptX(): void {
     69        if ( isset( self::$cryptXOptions['version'] ) && version_compare( CRYPTX_VERSION, self::$cryptXOptions['version'] ) > 0 ) {
     70            $this->updateCryptXSettings();
     71        }
     72        foreach ( self::$cryptXOptions['filter'] as $filter ) {
     73            if ( @self::$cryptXOptions[ $filter ] ) {
     74                $this->addPluginFilters( $filter );
     75            }
     76        }
     77        add_action( 'activate_' . CRYPTX_BASENAME, [ $this, 'installCryptX' ] );
     78        add_action( 'wp_enqueue_scripts', [ $this, 'loadJavascriptFiles' ] );
     79        if ( @self::$cryptXOptions['metaBox'] ) {
     80            add_action( 'admin_menu', [ $this, 'metaBox' ] );
     81            add_action( 'wp_insert_post', [ $this, 'addPostIdToExcludedList' ] );
     82            add_action( 'wp_update_post', [ $this, 'addPostIdToExcludedList' ] );
     83        }
     84        add_filter( 'plugin_row_meta', 'rw_cryptx_init_row_meta', 10, 2 );
     85        add_filter( 'init', [ $this, 'cryptXtinyUrl' ] );
     86        add_shortcode( 'cryptx', [ $this, 'cryptXShortcode' ] );
     87    }
    8888
    8989    /**
     
    9595     * @return array The array of default options.
    9696     */
    97     function getCryptXOptionsDefaults(): array
    98     {
    99         $firstFont = $this->getFilesInDirectory( CRYPTX_DIR_PATH . 'fonts', ["ttf"]);
    100         return array_merge(self::$defaults, [ 'version' => CRYPTX_VERSION, 'c2i_font' => $firstFont[0] ]);
     97    function getCryptXOptionsDefaults(): array {
     98        $firstFont = $this->getFilesInDirectory( CRYPTX_DIR_PATH . 'fonts', [ "ttf" ] );
     99
     100        return array_merge( self::$defaults, [ 'version' => CRYPTX_VERSION, 'c2i_font' => $firstFont[0] ] );
    101101    }
    102102
     
    106106     * @return array The cryptX options array with default values.
    107107     */
    108     function loadCryptXOptionsWithDefaults(): array
    109     {
    110         $defaultValues = $this->getCryptXOptionsDefaults();
    111         $currentOptions = get_option('cryptX');
    112         return wp_parse_args($currentOptions, $defaultValues);
     108    function loadCryptXOptionsWithDefaults(): array {
     109        $defaultValues  = $this->getCryptXOptionsDefaults();
     110        $currentOptions = get_option( 'cryptX' );
     111
     112        return wp_parse_args( $currentOptions, $defaultValues );
    113113    }
    114114
     
    120120     * @return void
    121121     */
    122     function saveCryptXOptions( array $saveOptions): void {
    123         update_option( 'cryptX', wp_parse_args( $saveOptions, $this->loadCryptXOptionsWithDefaults() ) );
    124     }
    125 
    126     /**
    127      * Processes the [cryptx] shortcode.
    128      *
    129      * @param array $atts The shortcode attributes.
    130      * @param string $content The content wrapped in the shortcode.
    131      *
    132      * @return string The processed content.
    133      */
    134     function cryptXShortcode( array $atts, string $content): string
    135     {
    136         if (@self::$cryptXOptions['autolink']) {
    137             $content = $this->addLinkToEmailAddresses($content, true);
    138         }
    139 
    140         return $this->encryptAndLinkContent($content);
     122    function saveCryptXOptions( array $saveOptions ): void {
     123        update_option( 'cryptX', wp_parse_args( $saveOptions, $this->loadCryptXOptionsWithDefaults() ) );
     124    }
     125
     126    /**
     127     * Generates a shortcode for encrypting email addresses in search results.
     128     *
     129     * @param array $atts An associative array of attributes for the shortcode.
     130     * @param string $content The content inside the shortcode.
     131     * @param string $tag The shortcode tag.
     132     *
     133     * @return string The encrypted search results content.
     134     */
     135    function cryptXShortcode( array $atts = [], string $content = '', string $tag = '' ): string {
     136        if ( isset( $atts['encoded'] ) && $atts['encoded'] == "true" ) {
     137            foreach ( $atts as $key => $value ) {
     138                $atts[ $key ] = $this->decodeString( $value );
     139            }
     140            unset( $atts['encoded'] );
     141        }
     142
     143        self::$cryptXOptions = shortcode_atts( $this->getCryptXOptionsDefaults(), array_change_key_case( $atts, CASE_LOWER ), $tag );
     144        if ( @self::$cryptXOptions['autolink'] ) {
     145            $content = $this->addLinkToEmailAddresses( $content, true );
     146        }
     147        $content             = $this->encryptAndLinkContent( $content, true );
     148        self::$cryptXOptions = $this->getCryptXOptionsDefaults();
     149
     150        return $content;
    141151    }
    142152
     
    148158     * @return string The encrypted and linked content.
    149159     */
    150     function encryptAndLinkContent( string $content): string {
    151         $content = $this->findEmailAddressesInContent($content, true);
    152         $content = $this->replaceEmailInContent($content, true);
    153         return $content;
    154     }
    155     /**
    156      *  create image from tinyurl
    157      *
    158      *  @return image
    159      */
    160     function cryptXtinyUrl() : void
    161     {
    162         $url                 = $_SERVER['REQUEST_URI'];
     160    function encryptAndLinkContent( string $content, bool $shortcode = false ): string {
     161        $content = $this->findEmailAddressesInContent( $content, $shortcode );
     162
     163        return $this->replaceEmailInContent( $content, $shortcode );
     164    }
     165
     166    /**
     167     * Generates and returns a tiny URL image.
     168     *
     169     * @return void
     170     */
     171    function cryptXtinyUrl(): void {
     172        $url    = $_SERVER['REQUEST_URI'];
    163173        $params = explode( '/', $url );
    164174        if ( count( $params ) > 1 ) {
    165             $tiny_url = $params[count( $params ) -2];
    166             if ( $tiny_url == md5( get_bloginfo('url') ) ) {
    167                 $font = CRYPTX_DIR_PATH . 'fonts/' . self::$cryptXOptions['c2i_font'];
    168                 $msg = $params[count( $params ) -1];
    169                 $size = self::$cryptXOptions['c2i_fontSize'];
    170                 $pad = 1;
     175            $tiny_url = $params[ count( $params ) - 2 ];
     176            if ( $tiny_url == md5( get_bloginfo( 'url' ) ) ) {
     177                $font        = CRYPTX_DIR_PATH . 'fonts/' . self::$cryptXOptions['c2i_font'];
     178                $msg         = $params[ count( $params ) - 1 ];
     179                $size        = self::$cryptXOptions['c2i_fontSize'];
     180                $pad         = 1;
    171181                $transparent = 1;
    172                 $rgb = str_replace("#", "", self::$cryptXOptions['c2i_fontRGB']);
    173                 $red = hexdec(substr($rgb,0,2));
    174                 $grn = hexdec(substr($rgb,2,2));
    175                 $blu = hexdec(substr($rgb,4,2));
    176                 $bg_red = 255 - $red;
    177                 $bg_grn = 255 - $grn;
    178                 $bg_blu = 255 - $blu;
    179                 $width = 0;
    180                 $height = 0;
    181                 $offset_x = 0;
    182                 $offset_y = 0;
    183                 $bounds = array();
    184                 $image = "";
    185                 $bounds = ImageTTFBBox($size, 0, $font, "W");
    186                 $font_height = abs($bounds[7]-$bounds[1]);
    187                 $bounds = ImageTTFBBox($size, 0, $font, $msg);
    188                 $width = abs($bounds[4]-$bounds[6]);
    189                 $height = abs($bounds[7]-$bounds[1]);
    190                 $offset_y = $font_height+abs(($height - $font_height)/2)-1;
    191                 $offset_x = 0;
    192                 $image = imagecreatetruecolor($width+($pad*2),$height+($pad*2));
    193                 imagesavealpha($image, true);
    194                 $foreground = ImageColorAllocate($image, $red, $grn, $blu);
    195                 $background = imagecolorallocatealpha($image, 0, 0, 0, 127);
    196                 imagefill($image, 0, 0, $background);
    197                 ImageTTFText($image, $size, 0, $offset_x+$pad, $offset_y+$pad, $foreground, $font, $msg);
    198                 Header("Content-type: image/png");
    199                 imagePNG($image);
     182                $rgb         = str_replace( "#", "", self::$cryptXOptions['c2i_fontRGB'] );
     183                $red         = hexdec( substr( $rgb, 0, 2 ) );
     184                $grn         = hexdec( substr( $rgb, 2, 2 ) );
     185                $blu         = hexdec( substr( $rgb, 4, 2 ) );
     186                $bg_red      = 255 - $red;
     187                $bg_grn      = 255 - $grn;
     188                $bg_blu      = 255 - $blu;
     189                $width       = 0;
     190                $height      = 0;
     191                $offset_x    = 0;
     192                $offset_y    = 0;
     193                $bounds      = array();
     194                $image       = "";
     195                $bounds      = ImageTTFBBox( $size, 0, $font, "W" );
     196                $font_height = abs( $bounds[7] - $bounds[1] );
     197                $bounds      = ImageTTFBBox( $size, 0, $font, $msg );
     198                $width       = abs( $bounds[4] - $bounds[6] );
     199                $height      = abs( $bounds[7] - $bounds[1] );
     200                $offset_y    = $font_height + abs( ( $height - $font_height ) / 2 ) - 1;
     201                $offset_x    = 0;
     202                $image       = imagecreatetruecolor( $width + ( $pad * 2 ), $height + ( $pad * 2 ) );
     203                imagesavealpha( $image, true );
     204                $foreground = ImageColorAllocate( $image, $red, $grn, $blu );
     205                $background = imagecolorallocatealpha( $image, 0, 0, 0, 127 );
     206                imagefill( $image, 0, 0, $background );
     207                ImageTTFText( $image, $size, 0, round( $offset_x + $pad, 0 ), round( $offset_y + $pad, 0 ), $foreground, $font, $msg );
     208                Header( "Content-type: image/png" );
     209                imagePNG( $image );
    200210                die;
    201211            }
     
    214224     * @return void
    215225     */
    216     function addPluginFilters( string $filterName): void
    217     {
     226    function addPluginFilters( string $filterName ): void {
    218227        global $shortcode_tags;
    219         if ( array_key_exists('autolink', self::$cryptXOptions) && self::$cryptXOptions['autolink']) {
    220             $this->addAutoLinkFilters($filterName);
    221             if (!empty($shortcode_tags)) {
    222                 $this->addAutoLinkFilters($filterName, 11);
     228        if ( array_key_exists( 'autolink', self::$cryptXOptions ) && self::$cryptXOptions['autolink'] ) {
     229            $this->addAutoLinkFilters( $filterName );
     230            if ( ! empty( $shortcode_tags ) ) {
     231                $this->addAutoLinkFilters( $filterName, 11 );
    223232                //add_filter($filterName, [$this,'autolink'], 11);
    224233            }
    225234        }
    226         $this->addOtherFilters($filterName);
     235        $this->addOtherFilters( $filterName );
    227236    }
    228237
     
    236245     * @return void
    237246     */
    238     function addAutoLinkFilters( string $filterName, $prio = 5): void
    239     {
    240         add_filter($filterName, [$this, 'addLinkToEmailAddresses' ], $prio);
     247    function addAutoLinkFilters( string $filterName, $prio = 5 ): void {
     248        add_filter( $filterName, [ $this, 'addLinkToEmailAddresses' ], $prio );
    241249    }
    242250
     
    252260     * @return void
    253261     */
    254     function addOtherFilters( string $filterName): void
    255     {
    256         add_filter($filterName, [$this, 'findEmailAddressesInContent' ], 12);
    257         add_filter($filterName, [$this,'replaceEmailInContent'], 13);
     262    function addOtherFilters( string $filterName ): void {
     263        add_filter( $filterName, [ $this, 'findEmailAddressesInContent' ], 12 );
     264        add_filter( $filterName, [ $this, 'replaceEmailInContent' ], 13 );
    258265    }
    259266
     
    265272     * @return bool Returns true if the ID is excluded, false otherwise.
    266273     */
    267     function isIdExcluded( int $ID): bool
    268     {
    269         $excludedIds = explode(",", self::$cryptXOptions['excludedIDs']);
    270         return in_array($ID, $excludedIds);
     274    function isIdExcluded( int $ID ): bool {
     275        $excludedIds = explode( ",", self::$cryptXOptions['excludedIDs'] );
     276
     277        return in_array( $ID, $excludedIds );
    271278    }
    272279
     
    279286     * @param string $content The
    280287     */
    281     function replaceEmailInContent( string $content, bool $isShortcode=false): string {
     288    function replaceEmailInContent( string $content, bool $isShortcode = false ): string {
    282289        global $post;
    283         $postId = (is_object($post))? $post->ID : -1;
    284         if ( !$this->isIdExcluded($postId) || $isShortcode ) {
    285             $content = $this->replaceEmailWithLinkText($content);
    286         }
     290        $postId = ( is_object( $post ) ) ? $post->ID : - 1;
     291        if ( ! $this->isIdExcluded( $postId ) || $isShortcode ) {
     292            $content = $this->replaceEmailWithLinkText( $content );
     293        }
     294
    287295        return $content;
    288296    }
     
    295303     * @return string The content with email addresses replaced with link text.
    296304     */
    297     function replaceEmailWithLinkText( string $content): string
    298     {
     305    function replaceEmailWithLinkText( string $content ): string {
    299306        $emailPattern = "/([_a-zA-Z0-9-+]+(\.[_a-zA-Z0-9-+]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,}))/i";
    300         return preg_replace_callback($emailPattern, [$this,'encodeEmailToLinkText'], $content );
     307
     308        return preg_replace_callback( $emailPattern, [ $this, 'encodeEmailToLinkText' ], $content );
    301309    }
    302310
     
    308316     * @return string The encoded link text.
    309317     */
    310     function encodeEmailToLinkText( array $Match): string {
    311         if($this->in_white_list($Match)) return $Match[1];
    312         switch (self::$cryptXOptions['opt_linktext']) {
     318    function encodeEmailToLinkText( array $Match ): string {
     319        if ( $this->inWhiteList( $Match ) ) {
     320            return $Match[1];
     321        }
     322        switch ( self::$cryptXOptions['opt_linktext'] ) {
    313323            case 1:
    314324                $text = $this->getLinkText();
     
    319329            case 3:
    320330                $img_url = wp_get_attachment_url( self::$cryptXOptions['alt_uploadedimage'] );
    321                 $text = $this->getUploadedImage($img_url);
    322                 self::$imageCounter++;
     331                $text    = $this->getUploadedImage( $img_url );
     332                self::$imageCounter ++;
    323333                break;
    324334            case 4:
    325                 $text = antispambot($Match[1]);
     335                $text = antispambot( $Match[1] );
    326336                break;
    327337            case 5:
    328                 $text = $this->getImageFromText($Match);
    329                 self::$imageCounter++;
     338                $text = $this->getImageFromText( $Match );
     339                self::$imageCounter ++;
    330340                break;
    331341            default:
    332                 $text = $this->getDefaultLinkText($Match);
     342                $text = $this->getDefaultLinkText( $Match );
    333343        }
    334344
     
    343353     * @return bool True if the match is in the whitelist, false otherwise.
    344354     */
    345     function in_white_list( array $Match): bool
    346     {
    347         $whiteList = array_filter(array_map('trim', explode(",", self::$cryptXOptions['whiteList'])));
    348         $tmp = explode(".", $Match[0]);
    349         return in_array(end($tmp), $whiteList);
     355    function inWhiteList( array $Match ): bool {
     356        $whiteList = array_filter( array_map( 'trim', explode( ",", self::$cryptXOptions['whiteList'] ) ) );
     357        $tmp       = explode( ".", $Match[0] );
     358
     359        return in_array( end( $tmp ), $whiteList );
    350360    }
    351361
     
    364374     * @return string The HTML image tag
    365375     */
    366     function getLinkImage(): string
    367     {
    368         return "<img src=\"" . self::$cryptXOptions['alt_linkimage'] . "\" class=\"cryptxImage\" alt=\"" . self::$cryptXOptions['alt_linkimage_title'] . "\" title=\"" . antispambot(self::$cryptXOptions['alt_linkimage_title']) . "\" />";
     376    function getLinkImage(): string {
     377        return "<img src=\"" . self::$cryptXOptions['alt_linkimage'] . "\" class=\"cryptxImage\" alt=\"" . self::$cryptXOptions['alt_linkimage_title'] . "\" title=\"" . antispambot( self::$cryptXOptions['alt_linkimage_title'] ) . "\" />";
    369378    }
    370379
     
    376385     * @return string The HTML tag for the image.
    377386     */
    378     function getUploadedImage( string $img_url): string
    379     {
    380         return "<img src=\"" . $img_url . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . self::$cryptXOptions['http_linkimage_title'] . " title=\"" . antispambot( self::$cryptXOptions['http_linkimage_title']) . "\" />";
     387    function getUploadedImage( string $img_url ): string {
     388        return "<img src=\"" . $img_url . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . self::$cryptXOptions['http_linkimage_title'] . " title=\"" . antispambot( self::$cryptXOptions['http_linkimage_title'] ) . "\" />";
    381389    }
    382390
     
    388396     * @return string Returns the HTML image element.
    389397     */
    390     function getImageFromText( array $Match): string
    391     {
    392         return "<img src=\"" . get_bloginfo('url') . "/" . md5( get_bloginfo('url') ) . "/" . antispambot($Match[1]) . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . antispambot($Match[1]) . "\" title=\"" . antispambot($Match[1]) . "\" />";
     398    function getImageFromText( array $Match ): string {
     399        return "<img src=\"" . get_bloginfo( 'url' ) . "/" . md5( get_bloginfo( 'url' ) ) . "/" . antispambot( $Match[1] ) . "\" class=\"cryptxImage cryptxImage_" . self::$imageCounter . "\" alt=\"" . antispambot( $Match[1] ) . "\" title=\"" . antispambot( $Match[1] ) . "\" />";
    393400    }
    394401
     
    404411     *                     for each element.
    405412     */
    406     function getDefaultLinkText( array $Match): string
    407     {
    408         $text = str_replace("@", self::$cryptXOptions['at'], $Match[1]);
    409         return str_replace(".", self::$cryptXOptions['dot'], $text);
     413    function getDefaultLinkText( array $Match ): string {
     414        $text = str_replace( "@", self::$cryptXOptions['at'], $Match[1] );
     415
     416        return str_replace( ".", self::$cryptXOptions['dot'], $text );
    410417    }
    411418
     
    419426     * @return array An array of file names that match the filter.
    420427     */
    421     function getFilesInDirectory( string $path, array $filter): array
    422     {
    423         $directoryHandle = opendir($path);
     428    function getFilesInDirectory( string $path, array $filter ): array {
     429        $directoryHandle  = opendir( $path );
    424430        $directoryContent = array();
    425         while ($file = readdir($directoryHandle)) {
    426             $fileExtension = substr(strtolower($file), -3);
    427             if (in_array($fileExtension, $filter)) {
     431        while ( $file = readdir( $directoryHandle ) ) {
     432            $fileExtension = substr( strtolower( $file ), - 3 );
     433            if ( in_array( $fileExtension, $filter ) ) {
    428434                $directoryContent[] = $file;
    429435            }
    430436        }
     437
    431438        return $directoryContent;
    432439    }
     
    440447     * @return string|null The content with encrypted email addresses, or null if $content is null.
    441448     */
    442     function findEmailAddressesInContent( ?string $content, bool $shortcode = false): ?string
    443     {
    444         global $post;
    445 
    446         if ($content === null) return null;
    447 
    448         $postId = (is_object($post))? $post->ID : -1;
    449 
    450         $isIdExcluded = $this->isIdExcluded($postId);
    451         $mailtoRegex = '/<a (.*?)(href=("|\')mailto:(.*?)("|\')(.*?)|)>\s*(.*?)\s*<\/a>/i';
    452 
    453         if ((!$isIdExcluded || $shortcode !== null)) {
    454             $content = preg_replace_callback($mailtoRegex, [$this, 'encryptEmailAddress' ], $content);
     449    function findEmailAddressesInContent( ?string $content, bool $shortcode = false ): ?string {
     450        global $post;
     451
     452        if ( $content === null ) {
     453            return null;
     454        }
     455
     456        $postId = ( is_object( $post ) ) ? $post->ID : - 1;
     457
     458        $isIdExcluded = $this->isIdExcluded( $postId );
     459        $mailtoRegex  = '/<a (.*?)(href=("|\')mailto:(.*?)("|\')(.*?)|)>\s*(.*?)\s*<\/a>/i';
     460
     461        if ( ( ! $isIdExcluded || $shortcode !== null ) ) {
     462            $content = preg_replace_callback( $mailtoRegex, [ $this, 'encryptEmailAddress' ], $content );
    455463        }
    456464
     
    465473     * @return string The search results with encrypted email addresses.
    466474     */
    467     function encryptEmailAddress( array $searchResults): string
    468     {
     475    function encryptEmailAddress( array $searchResults ): string {
    469476        $originalValue = $searchResults[0];
    470477
    471         if(strpos($searchResults[self::INDEX_TO_CHECK], '@') === self::NOT_FOUND) {
     478        if ( strpos( $searchResults[ self::INDEX_TO_CHECK ], '@' ) === self::NOT_FOUND ) {
    472479            return $originalValue;
    473480        }
    474481
    475         $mailReference = self::MAIL_IDENTIFIER . $searchResults[self::INDEX_TO_CHECK];
     482        $mailReference = self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK ];
    476483
    477484        if ( str_starts_with( $searchResults[ self::INDEX_TO_CHECK ], self::SUBJECT_IDENTIFIER ) ) {
     
    480487
    481488        $return = $originalValue;
    482         if (!empty(self::$cryptXOptions['java'])) {
    483             $javaHandler="javascript:DeCryptX('" . $this->generateHashFromString($searchResults[self::INDEX_TO_CHECK]) . "')";
    484             $return = str_replace(self::MAIL_IDENTIFIER.$searchResults[self::INDEX_TO_CHECK], $javaHandler, $originalValue);
    485         }
    486 
    487         $return = str_replace($mailReference, antispambot($mailReference), $return);
    488 
    489         if(!empty(self::$cryptXOptions['css_id'])) {
    490             $return = preg_replace(self::PATTERN, '$1" id="'.self::$cryptXOptions['css_id'] . '">', $return );
    491         }
    492 
    493         if(!empty(self::$cryptXOptions['css_class'])) {
    494             $return = preg_replace(self::PATTERN, '$1" class="'.self::$cryptXOptions['css_class'] . '">', $return );
     489        if ( ! empty( self::$cryptXOptions['java'] ) ) {
     490            $javaHandler = "javascript:DeCryptX('" . $this->generateHashFromString( $searchResults[ self::INDEX_TO_CHECK ] ) . "')";
     491            $return      = str_replace( self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK ], $javaHandler, $originalValue );
     492        }
     493
     494        $return = str_replace( $mailReference, antispambot( $mailReference ), $return );
     495
     496        if ( ! empty( self::$cryptXOptions['css_id'] ) ) {
     497            $return = preg_replace( self::PATTERN, '$1" id="' . self::$cryptXOptions['css_id'] . '">', $return );
     498        }
     499
     500        if ( ! empty( self::$cryptXOptions['css_class'] ) ) {
     501            $return = preg_replace( self::PATTERN, '$1" class="' . self::$cryptXOptions['css_class'] . '">', $return );
    495502        }
    496503
     
    506513     * @return string The generated hash string.
    507514     */
    508     function generateHashFromString( string $inputString): string
    509     {
    510         $inputString = str_replace("&", "&", $inputString);
    511         $crypt = '';
    512 
    513         for ($i = 0; $i < strlen($inputString); $i++) {
     515    function generateHashFromString( string $inputString ): string {
     516        $inputString = str_replace( "&", "&", $inputString );
     517        $crypt       = '';
     518
     519        for ( $i = 0; $i < strlen( $inputString ); $i ++ ) {
    514520            do {
    515                 $salt = mt_rand(0, 3);
    516                 $asciiValue = ord(substr($inputString, $i)) + $salt;
    517                 if (8364 <= $asciiValue) {
     521                $salt       = mt_rand( 0, 3 );
     522                $asciiValue = ord( substr( $inputString, $i ) ) + $salt;
     523                if ( 8364 <= $asciiValue ) {
    518524                    $asciiValue = 128;
    519525                }
    520             } while (in_array($asciiValue, self::ASCII_VALUES_BLACKLIST));
    521 
    522             $crypt .= $salt . chr($asciiValue);
    523         }
     526            } while ( in_array( $asciiValue, self::ASCII_VALUES_BLACKLIST ) );
     527
     528            $crypt .= $salt . chr( $asciiValue );
     529        }
     530
    524531        return $crypt;
    525532    }
     
    535542     * @return string The content with emails auto-linked.
    536543     */
    537     function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string
    538     {
     544    function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string {
    539545        global $post;
    540546        $postID = is_object( $post ) ? $post->ID : - 1;
     
    575581    function installCryptX(): void {
    576582        global $wpdb;
    577         self::$cryptXOptions['admin_notices_deprecated'] =true;
    578         if ( self::$cryptXOptions['excludedIDs'] == "") {
    579             $tmp = array();
    580             $excludes = $wpdb->get_results("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff' AND meta_value = 'true'");
    581             if(count($excludes) > 0) {
    582                 foreach ($excludes as $exclude) {
     583        self::$cryptXOptions['admin_notices_deprecated'] = true;
     584        if ( self::$cryptXOptions['excludedIDs'] == "" ) {
     585            $tmp      = array();
     586            $excludes = $wpdb->get_results( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff' AND meta_value = 'true'" );
     587            if ( count( $excludes ) > 0 ) {
     588                foreach ( $excludes as $exclude ) {
    583589                    $tmp[] = $exclude->post_id;
    584590                }
    585                 sort($tmp);
    586                 self::$cryptXOptions['excludedIDs'] = implode(",", $tmp);
    587                 update_option( 'cryptX', self::$cryptXOptions);
     591                sort( $tmp );
     592                self::$cryptXOptions['excludedIDs'] = implode( ",", $tmp );
     593                update_option( 'cryptX', self::$cryptXOptions );
    588594                self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); // reread Options
    589                 $wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff'");
    590             }
    591         }
    592         if (empty(self::$cryptXOptions['c2i_font'])) {
     595                $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = 'cryptxoff'" );
     596            }
     597        }
     598        if ( empty( self::$cryptXOptions['c2i_font'] ) ) {
    593599            self::$cryptXOptions['c2i_font'] = CRYPTX_DIR_PATH . 'fonts/' . $firstFont[0];
    594600        }
    595         if (empty(self::$cryptXOptions['c2i_fontSize'])) {
     601        if ( empty( self::$cryptXOptions['c2i_fontSize'] ) ) {
    596602            self::$cryptXOptions['c2i_fontSize'] = 10;
    597603        }
    598         if (empty(self::$cryptXOptions['c2i_fontRGB'])) {
     604        if ( empty( self::$cryptXOptions['c2i_fontRGB'] ) ) {
    599605            self::$cryptXOptions['c2i_fontRGB'] = '000000';
    600606        }
    601         update_option( 'cryptX', self::$cryptXOptions);
     607        update_option( 'cryptX', self::$cryptXOptions );
    602608        self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); // reread Options
    603609    }
    604610
    605     function addHooksHelper($function_name, $hook_name): void {
    606         if ( function_exists($function_name) ) {
    607             call_user_func($function_name, 'cryptx', 'CryptX', [$this, 'metaCheckbox' ], $hook_name);
     611    function addHooksHelper( $function_name, $hook_name ): void {
     612        if ( function_exists( $function_name ) ) {
     613            call_user_func( $function_name, 'cryptx', 'CryptX', [ $this, 'metaCheckbox' ], $hook_name );
    608614        } else {
    609             add_action("dbx_{$hook_name}_sidebar", [$this, 'metaOptionFieldset' ]);
     615            add_action( "dbx_{$hook_name}_sidebar", [ $this, 'metaOptionFieldset' ] );
    610616        }
    611617    }
    612618
    613619    function metaBox(): void {
    614         $this->addHooksHelper('add_meta_box', 'post');
    615         $this->addHooksHelper('add_meta_box', 'page');
     620        $this->addHooksHelper( 'add_meta_box', 'post' );
     621        $this->addHooksHelper( 'add_meta_box', 'page' );
    616622    }
    617623
     
    622628     * functionality for the current post or page. If the current post or page ID is excluded
    623629     **/
    624     function metaCheckbox(): void
    625     {
     630    function metaCheckbox(): void {
    626631        global $post;
    627632        ?>
    628         <label><input type="checkbox" name="disable_cryptx_pageid" <?php if ($this->isIdExcluded($post->ID)) { echo 'checked="checked"'; } ?>/>
    629         Disable CryptX for this post/page</label>
     633        <label><input type="checkbox" name="disable_cryptx_pageid" <?php if ( $this->isIdExcluded( $post->ID ) ) {
     634                echo 'checked="checked"';
     635            } ?>/>
     636            Disable CryptX for this post/page</label>
    630637        <?php
    631638    }
     
    637644     * @return void
    638645     */
    639     function metaOptionFieldset(): void
    640     {
     646    function metaOptionFieldset(): void {
    641647        global $post;
    642         if ( current_user_can('edit_posts') ) { ?>
    643             <fieldset id="cryptxoption" class="dbx-box">
    644                 <h3 class="dbx-handle">CryptX</h3>
    645                 <div class="dbx-content">
    646                     <label><input type="checkbox" name="disable_cryptx_pageid" <?php if ($this->isIdExcluded($post->ID)) { echo 'checked="checked"'; } ?>/> Disable CryptX for this post/page</label>
    647                 </div>
    648             </fieldset>
     648        if ( current_user_can( 'edit_posts' ) ) { ?>
     649            <fieldset id="cryptxoption" class="dbx-box">
     650                <h3 class="dbx-handle">CryptX</h3>
     651                <div class="dbx-content">
     652                    <label><input type="checkbox"
     653                                  name="disable_cryptx_pageid" <?php if ( $this->isIdExcluded( $post->ID ) ) {
     654                            echo 'checked="checked"';
     655                        } ?>/> Disable CryptX for this post/page</label>
     656                </div>
     657            </fieldset>
    649658            <?php
    650659        }
     
    658667     * @return void
    659668     */
    660     function addPostIdToExcludedList( int $postId): void {
    661         $postId                             = wp_is_post_revision($postId) ?: $postId;
    662         $excludedIds                        = $this->updateExcludedIdsList(self::$cryptXOptions['excludedIDs'], $postId);
    663         self::$cryptXOptions['excludedIDs'] = implode(",", array_filter($excludedIds));
    664         update_option('cryptX', self::$cryptXOptions);
     669    function addPostIdToExcludedList( int $postId ): void {
     670        $postId                             = wp_is_post_revision( $postId ) ?: $postId;
     671        $excludedIds                        = $this->updateExcludedIdsList( self::$cryptXOptions['excludedIDs'], $postId );
     672        self::$cryptXOptions['excludedIDs'] = implode( ",", array_filter( $excludedIds ) );
     673        update_option( 'cryptX', self::$cryptXOptions );
    665674    }
    666675
     
    673682     * @return array The updated excluded IDs list as an array, with the ID removed if it existed and added if necessary.
    674683     */
    675     function updateExcludedIdsList(string $excludedIds, int $postId): array {
    676         $excludedIdsArray = explode(",", $excludedIds);
    677         $excludedIdsArray = $this->removePostIdFromExcludedIds($excludedIdsArray, $postId);
    678         $excludedIdsArray = $this->addPostIdToExcludedIdsIfNecessary($excludedIdsArray, $postId);
    679         return $this->makeExcludedIdsUniqueAndSorted($excludedIdsArray);
     684    function updateExcludedIdsList( string $excludedIds, int $postId ): array {
     685        $excludedIdsArray = explode( ",", $excludedIds );
     686        $excludedIdsArray = $this->removePostIdFromExcludedIds( $excludedIdsArray, $postId );
     687        $excludedIdsArray = $this->addPostIdToExcludedIdsIfNecessary( $excludedIdsArray, $postId );
     688
     689        return $this->makeExcludedIdsUniqueAndSorted( $excludedIdsArray );
    680690    }
    681691
     
    688698     * @return array The updated array of excluded IDs without the specified post ID.
    689699     */
    690     function removePostIdFromExcludedIds(array $excludedIds, int $postId): array {
    691         foreach($excludedIds as $key => $id) {
    692             if($id == $postId) {
    693                 unset($excludedIds[$key]);
     700    function removePostIdFromExcludedIds( array $excludedIds, int $postId ): array {
     701        foreach ( $excludedIds as $key => $id ) {
     702            if ( $id == $postId ) {
     703                unset( $excludedIds[ $key ] );
    694704                break;
    695705            }
    696706        }
     707
    697708        return $excludedIds;
    698709    }
     
    706717     * @return array The updated array of excluded IDs.
    707718     */
    708     function addPostIdToExcludedIdsIfNecessary(array $excludedIds, int $postId): array {
    709         if (isset($_POST['disable_cryptx_pageid'])) {
     719    function addPostIdToExcludedIdsIfNecessary( array $excludedIds, int $postId ): array {
     720        if ( isset( $_POST['disable_cryptx_pageid'] ) ) {
    710721            $excludedIds[] = $postId;
    711722        }
     723
    712724        return $excludedIds;
    713725    }
     
    720732     * @return array The array of excluded IDs with duplicate values removed and sorted in ascending order.
    721733     */
    722     function makeExcludedIdsUniqueAndSorted(array $excludedIds): array {
    723         $excludedIds = array_unique($excludedIds);
    724         sort($excludedIds);
     734    function makeExcludedIdsUniqueAndSorted( array $excludedIds ): array {
     735        $excludedIds = array_unique( $excludedIds );
     736        sort( $excludedIds );
     737
    725738        return $excludedIds;
    726739    }
     
    734747     * @return void
    735748     */
    736     function showMessage($message, $errormsg = false): void {
    737         if ($errormsg) {
     749    function showMessage( $message, $errormsg = false ): void {
     750        if ( $errormsg ) {
    738751            echo '<div id="message" class="error">';
    739         }
    740         else {
     752        } else {
    741753            echo '<div id="message" class="updated fade">';
    742754        }
     
    751763     */
    752764    function getDomain(): string {
    753         return $this->trimSlashFromDomain($this->removeProtocolFromUrl($this->getSiteUrl()));
     765        return $this->trimSlashFromDomain( $this->removeProtocolFromUrl( $this->getSiteUrl() ) );
    754766    }
    755767
     
    770782     * @return string The URL string without the protocol.
    771783     */
    772     function removeProtocolFromUrl(string $url): string
    773     {
     784    function removeProtocolFromUrl( string $url ): string {
    774785        return preg_replace( '|https?://|', '', $url );
    775786    }
     
    782793     * @return string The domain with the trailing slash removed.
    783794     */
    784     function trimSlashFromDomain(string $domain): string
    785     {
     795    function trimSlashFromDomain( string $domain ): string {
    786796        if ( $slashPosition = strpos( $domain, '/' ) ) {
    787797            $domain = substr( $domain, 0, $slashPosition );
    788798        }
     799
    789800        return $domain;
    790801    }
     
    797808    function loadJavascriptFiles(): void {
    798809        wp_enqueue_script( 'cryptx-js', CRYPTX_DIR_URL . 'js/cryptx.min.js', false, false, self::$cryptXOptions['load_java'] );
    799         wp_enqueue_style( 'cryptx-styles', CRYPTX_DIR_URL . 'css/cryptx.css');
     810        wp_enqueue_style( 'cryptx-styles', CRYPTX_DIR_URL . 'css/cryptx.css' );
    800811    }
    801812
     
    810821     */
    811822    function updateCryptXSettings(): void {
    812         self::$cryptXOptions = get_option('cryptX');
    813         if( isset( self::$cryptXOptions['version'] ) && version_compare(CRYPTX_VERSION, self::$cryptXOptions['version']) > 0 ) {
    814             if( isset(self::$cryptXOptions['version']) ) unset(self::$cryptXOptions['version']);
    815             if( isset(self::$cryptXOptions['c2i_font']) ) unset(self::$cryptXOptions['c2i_font']);
    816             if( isset(self::$cryptXOptions['c2i_fontRGB']) ) self::$cryptXOptions['c2i_fontRGB'] = "#" . self::$cryptXOptions['c2i_fontRGB'];
    817             if( isset(self::$cryptXOptions['alt_uploadedimage']) && !is_int(self::$cryptXOptions['alt_uploadedimage'])) {
    818                 unset(self::$cryptXOptions['alt_uploadedimage']);
    819                 if( self::$cryptXOptions['opt_linktext'] == 3 ) unset(self::$cryptXOptions['opt_linktext']);
     823        self::$cryptXOptions = get_option( 'cryptX' );
     824        if ( isset( self::$cryptXOptions['version'] ) && version_compare( CRYPTX_VERSION, self::$cryptXOptions['version'] ) > 0 ) {
     825            if ( isset( self::$cryptXOptions['version'] ) ) {
     826                unset( self::$cryptXOptions['version'] );
     827            }
     828            if ( isset( self::$cryptXOptions['c2i_font'] ) ) {
     829                unset( self::$cryptXOptions['c2i_font'] );
     830            }
     831            if ( isset( self::$cryptXOptions['c2i_fontRGB'] ) ) {
     832                self::$cryptXOptions['c2i_fontRGB'] = "#" . self::$cryptXOptions['c2i_fontRGB'];
     833            }
     834            if ( isset( self::$cryptXOptions['alt_uploadedimage'] ) && ! is_int( self::$cryptXOptions['alt_uploadedimage'] ) ) {
     835                unset( self::$cryptXOptions['alt_uploadedimage'] );
     836                if ( self::$cryptXOptions['opt_linktext'] == 3 ) {
     837                    unset( self::$cryptXOptions['opt_linktext'] );
     838                }
    820839            }
    821840            self::$cryptXOptions = wp_parse_args( self::$cryptXOptions, $this->getCryptXOptionsDefaults() );
    822             update_option( 'cryptX', self::$cryptXOptions);
    823         }
     841            update_option( 'cryptX', self::$cryptXOptions );
     842        }
     843    }
     844
     845    /**
     846     * Encodes a string by replacing special characters with their corresponding HTML entities.
     847     *
     848     * @param string|null $str The string to be encoded.
     849     *
     850     * @return string The encoded string, or an array of encoded strings if an array was passed.
     851     */
     852    function encodeString( ?string $str ): string {
     853        $str     = htmlentities( $str, ENT_QUOTES, 'UTF-8' );
     854        $special = array(
     855            '[' => '&#91;',
     856            ']' => '&#93;',
     857        );
     858
     859        return str_replace( array_keys( $special ), array_values( $special ), $str );
     860    }
     861
     862    /**
     863     * Decodes a string that has been HTML entity encoded.
     864     *
     865     * @param string|null $str The string to decode. If null, an empty string is returned.
     866     *
     867     * @return string The decoded string.
     868     */
     869    function decodeString( ?string $str ): string {
     870        return html_entity_decode( $str, ENT_QUOTES, 'UTF-8' );
     871    }
     872
     873    function convertArrayToArgumentString( array $args = [] ): string {
     874        $string = "";
     875        if ( ! empty( $args ) ) {
     876            foreach ( $args as $key => $value ) {
     877                $string .= sprintf( " %s=\"%s\"", $key, $this->encodeString( $value ) );
     878            }
     879            $string .= " encoded=\"true\"";
     880        }
     881
     882        return $string;
    824883    }
    825884}
  • cryptx/trunk/cryptx.php

    r3102850 r3103107  
    44 * Plugin URI: http://weber-nrw.de/wordpress/cryptx/
    55 * Description: No more SPAM by spiders scanning you site for email addresses. With CryptX you can hide all your email addresses, with and without a mailto-link, by converting them using javascript or UNICODE.
    6  * Version: 3.4.4
     6 * Version: 3.4.5
    77 * Requires at least: 6.0
    88 * Author: Ralf Weber
     
    4242 * @return string The encrypted content wrapped in the Cryptx shortcode.
    4343 */
    44 function encryptx( ?string $content, string $args = "" ): string {
    45     return do_shortcode( '[cryptx]' . $content . '[/cryptx]' );
     44function encryptx( ?string $content, ?array $args ): string {
     45    $CryptX_instance = Cryptx\CryptX::getInstance();
     46    return do_shortcode( '[cryptx'. $CryptX_instance->convertArrayToArgumentString( $args ).']' . $content . '[/cryptx]' );
    4647}
  • cryptx/trunk/readme.txt

    r3102850 r3103107  
    55Requires at least: 6.0
    66Tested up to: 6.5
    7 Stable tag: 3.4.4
     7Stable tag: 3.4.5
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    2222
    2323== Changelog ==
     24= 3.4.5 =
     25* The "encryptx" template function has been revised so that it accepts arguments again, as in previous versions.
    2426= 3.4.4 =
    2527* changed type hinting of an argument to be string or null on some methods
Note: See TracChangeset for help on using the changeset viewer.