Changeset 3103107
- Timestamp:
- 06/15/2024 01:34:20 PM (19 months ago)
- Location:
- cryptx
- Files:
-
- 3 edited
- 5 copied
-
tags/3.4.5 (copied) (copied from cryptx/trunk)
-
tags/3.4.5/classes/CryptX.php (copied) (copied from cryptx/trunk/classes/CryptX.php) (39 diffs)
-
tags/3.4.5/cryptx.php (copied) (copied from cryptx/trunk/cryptx.php) (2 diffs)
-
tags/3.4.5/include/admin_presentation.php (copied) (copied from cryptx/trunk/include/admin_presentation.php)
-
tags/3.4.5/readme.txt (copied) (copied from cryptx/trunk/readme.txt) (2 diffs)
-
trunk/classes/CryptX.php (modified) (39 diffs)
-
trunk/cryptx.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
cryptx/tags/3.4.5/classes/CryptX.php
r3102850 r3103107 5 5 class CryptX { 6 6 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' ]; 13 13 14 14 private static ?CryptX $_instance = null; 15 15 private static array $cryptXOptions = []; 16 16 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' => '', 33 33 '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', 44 44 ); 45 45 private static int $imageCounter = 0; 46 private function __construct() 47 {46 47 private function __construct() { 48 48 self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); 49 49 } … … 58 58 * @return CryptX The instance of the CryptX class. 59 59 */ 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 ) ) { 63 62 self::$_instance = new self(); 64 63 } 64 65 65 return self::$_instance; 66 66 } 67 67 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 } 88 88 89 89 /** … … 95 95 * @return array The array of default options. 96 96 */ 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] ] ); 101 101 } 102 102 … … 106 106 * @return array The cryptX options array with default values. 107 107 */ 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 ); 113 113 } 114 114 … … 120 120 * @return void 121 121 */ 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; 141 151 } 142 152 … … 148 158 * @return string The encrypted and linked content. 149 159 */ 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 tinyurl157 * 158 * @return image159 * /160 function cryptXtinyUrl() : void161 {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']; 163 173 $params = explode( '/', $url ); 164 174 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; 171 181 $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 ); 200 210 die; 201 211 } … … 214 224 * @return void 215 225 */ 216 function addPluginFilters( string $filterName): void 217 { 226 function addPluginFilters( string $filterName ): void { 218 227 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 ); 223 232 //add_filter($filterName, [$this,'autolink'], 11); 224 233 } 225 234 } 226 $this->addOtherFilters( $filterName);235 $this->addOtherFilters( $filterName ); 227 236 } 228 237 … … 236 245 * @return void 237 246 */ 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 ); 241 249 } 242 250 … … 252 260 * @return void 253 261 */ 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 ); 258 265 } 259 266 … … 265 272 * @return bool Returns true if the ID is excluded, false otherwise. 266 273 */ 267 function isIdExcluded( int $ID ): bool268 {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 ); 271 278 } 272 279 … … 279 286 * @param string $content The 280 287 */ 281 function replaceEmailInContent( string $content, bool $isShortcode =false): string {288 function replaceEmailInContent( string $content, bool $isShortcode = false ): string { 282 289 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 287 295 return $content; 288 296 } … … 295 303 * @return string The content with email addresses replaced with link text. 296 304 */ 297 function replaceEmailWithLinkText( string $content): string 298 { 305 function replaceEmailWithLinkText( string $content ): string { 299 306 $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 ); 301 309 } 302 310 … … 308 316 * @return string The encoded link text. 309 317 */ 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'] ) { 313 323 case 1: 314 324 $text = $this->getLinkText(); … … 319 329 case 3: 320 330 $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 ++; 323 333 break; 324 334 case 4: 325 $text = antispambot( $Match[1]);335 $text = antispambot( $Match[1] ); 326 336 break; 327 337 case 5: 328 $text = $this->getImageFromText( $Match);329 self::$imageCounter ++;338 $text = $this->getImageFromText( $Match ); 339 self::$imageCounter ++; 330 340 break; 331 341 default: 332 $text = $this->getDefaultLinkText( $Match);342 $text = $this->getDefaultLinkText( $Match ); 333 343 } 334 344 … … 343 353 * @return bool True if the match is in the whitelist, false otherwise. 344 354 */ 345 function in _white_list( array $Match): bool346 {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 ); 350 360 } 351 361 … … 364 374 * @return string The HTML image tag 365 375 */ 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'] ) . "\" />"; 369 378 } 370 379 … … 376 385 * @return string The HTML tag for the image. 377 386 */ 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'] ) . "\" />"; 381 389 } 382 390 … … 388 396 * @return string Returns the HTML image element. 389 397 */ 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] ) . "\" />"; 393 400 } 394 401 … … 404 411 * for each element. 405 412 */ 406 function getDefaultLinkText( array $Match ): string407 {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 ); 410 417 } 411 418 … … 419 426 * @return array An array of file names that match the filter. 420 427 */ 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 ); 424 430 $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 ) ) { 428 434 $directoryContent[] = $file; 429 435 } 430 436 } 437 431 438 return $directoryContent; 432 439 } … … 440 447 * @return string|null The content with encrypted email addresses, or null if $content is null. 441 448 */ 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 ); 455 463 } 456 464 … … 465 473 * @return string The search results with encrypted email addresses. 466 474 */ 467 function encryptEmailAddress( array $searchResults): string 468 { 475 function encryptEmailAddress( array $searchResults ): string { 469 476 $originalValue = $searchResults[0]; 470 477 471 if (strpos($searchResults[self::INDEX_TO_CHECK], '@') === self::NOT_FOUND) {478 if ( strpos( $searchResults[ self::INDEX_TO_CHECK ], '@' ) === self::NOT_FOUND ) { 472 479 return $originalValue; 473 480 } 474 481 475 $mailReference = self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK];482 $mailReference = self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK ]; 476 483 477 484 if ( str_starts_with( $searchResults[ self::INDEX_TO_CHECK ], self::SUBJECT_IDENTIFIER ) ) { … … 480 487 481 488 $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 ); 495 502 } 496 503 … … 506 513 * @return string The generated hash string. 507 514 */ 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 ++ ) { 514 520 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 ) { 518 524 $asciiValue = 128; 519 525 } 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 524 531 return $crypt; 525 532 } … … 535 542 * @return string The content with emails auto-linked. 536 543 */ 537 function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string 538 { 544 function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string { 539 545 global $post; 540 546 $postID = is_object( $post ) ? $post->ID : - 1; … … 575 581 function installCryptX(): void { 576 582 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 ) { 583 589 $tmp[] = $exclude->post_id; 584 590 } 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 ); 588 594 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'] ) ) { 593 599 self::$cryptXOptions['c2i_font'] = CRYPTX_DIR_PATH . 'fonts/' . $firstFont[0]; 594 600 } 595 if ( empty(self::$cryptXOptions['c2i_fontSize'])) {601 if ( empty( self::$cryptXOptions['c2i_fontSize'] ) ) { 596 602 self::$cryptXOptions['c2i_fontSize'] = 10; 597 603 } 598 if ( empty(self::$cryptXOptions['c2i_fontRGB'])) {604 if ( empty( self::$cryptXOptions['c2i_fontRGB'] ) ) { 599 605 self::$cryptXOptions['c2i_fontRGB'] = '000000'; 600 606 } 601 update_option( 'cryptX', self::$cryptXOptions );607 update_option( 'cryptX', self::$cryptXOptions ); 602 608 self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); // reread Options 603 609 } 604 610 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 ); 608 614 } else { 609 add_action( "dbx_{$hook_name}_sidebar", [$this, 'metaOptionFieldset' ]);615 add_action( "dbx_{$hook_name}_sidebar", [ $this, 'metaOptionFieldset' ] ); 610 616 } 611 617 } 612 618 613 619 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' ); 616 622 } 617 623 … … 622 628 * functionality for the current post or page. If the current post or page ID is excluded 623 629 **/ 624 function metaCheckbox(): void 625 { 630 function metaCheckbox(): void { 626 631 global $post; 627 632 ?> 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> 630 637 <?php 631 638 } … … 637 644 * @return void 638 645 */ 639 function metaOptionFieldset(): void 640 { 646 function metaOptionFieldset(): void { 641 647 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> 649 658 <?php 650 659 } … … 658 667 * @return void 659 668 */ 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 ); 665 674 } 666 675 … … 673 682 * @return array The updated excluded IDs list as an array, with the ID removed if it existed and added if necessary. 674 683 */ 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 ); 680 690 } 681 691 … … 688 698 * @return array The updated array of excluded IDs without the specified post ID. 689 699 */ 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 ] ); 694 704 break; 695 705 } 696 706 } 707 697 708 return $excludedIds; 698 709 } … … 706 717 * @return array The updated array of excluded IDs. 707 718 */ 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'] ) ) { 710 721 $excludedIds[] = $postId; 711 722 } 723 712 724 return $excludedIds; 713 725 } … … 720 732 * @return array The array of excluded IDs with duplicate values removed and sorted in ascending order. 721 733 */ 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 725 738 return $excludedIds; 726 739 } … … 734 747 * @return void 735 748 */ 736 function showMessage( $message, $errormsg = false): void {737 if ( $errormsg) {749 function showMessage( $message, $errormsg = false ): void { 750 if ( $errormsg ) { 738 751 echo '<div id="message" class="error">'; 739 } 740 else { 752 } else { 741 753 echo '<div id="message" class="updated fade">'; 742 754 } … … 751 763 */ 752 764 function getDomain(): string { 753 return $this->trimSlashFromDomain( $this->removeProtocolFromUrl($this->getSiteUrl()));765 return $this->trimSlashFromDomain( $this->removeProtocolFromUrl( $this->getSiteUrl() ) ); 754 766 } 755 767 … … 770 782 * @return string The URL string without the protocol. 771 783 */ 772 function removeProtocolFromUrl(string $url): string 773 { 784 function removeProtocolFromUrl( string $url ): string { 774 785 return preg_replace( '|https?://|', '', $url ); 775 786 } … … 782 793 * @return string The domain with the trailing slash removed. 783 794 */ 784 function trimSlashFromDomain(string $domain): string 785 { 795 function trimSlashFromDomain( string $domain ): string { 786 796 if ( $slashPosition = strpos( $domain, '/' ) ) { 787 797 $domain = substr( $domain, 0, $slashPosition ); 788 798 } 799 789 800 return $domain; 790 801 } … … 797 808 function loadJavascriptFiles(): void { 798 809 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' ); 800 811 } 801 812 … … 810 821 */ 811 822 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 } 820 839 } 821 840 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 '[' => '[', 856 ']' => ']', 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; 824 883 } 825 884 } -
cryptx/tags/3.4.5/cryptx.php
r3102850 r3103107 4 4 * Plugin URI: http://weber-nrw.de/wordpress/cryptx/ 5 5 * 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. 46 * Version: 3.4.5 7 7 * Requires at least: 6.0 8 8 * Author: Ralf Weber … … 42 42 * @return string The encrypted content wrapped in the Cryptx shortcode. 43 43 */ 44 function encryptx( ?string $content, string $args = "" ): string { 45 return do_shortcode( '[cryptx]' . $content . '[/cryptx]' ); 44 function encryptx( ?string $content, ?array $args ): string { 45 $CryptX_instance = Cryptx\CryptX::getInstance(); 46 return do_shortcode( '[cryptx'. $CryptX_instance->convertArrayToArgumentString( $args ).']' . $content . '[/cryptx]' ); 46 47 } -
cryptx/tags/3.4.5/readme.txt
r3102850 r3103107 5 5 Requires at least: 6.0 6 6 Tested up to: 6.5 7 Stable tag: 3.4. 47 Stable tag: 3.4.5 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later … … 22 22 23 23 == Changelog == 24 = 3.4.5 = 25 * The "encryptx" template function has been revised so that it accepts arguments again, as in previous versions. 24 26 = 3.4.4 = 25 27 * changed type hinting of an argument to be string or null on some methods -
cryptx/trunk/classes/CryptX.php
r3102850 r3103107 5 5 class CryptX { 6 6 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' ]; 13 13 14 14 private static ?CryptX $_instance = null; 15 15 private static array $cryptXOptions = []; 16 16 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' => '', 33 33 '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', 44 44 ); 45 45 private static int $imageCounter = 0; 46 private function __construct() 47 {46 47 private function __construct() { 48 48 self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); 49 49 } … … 58 58 * @return CryptX The instance of the CryptX class. 59 59 */ 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 ) ) { 63 62 self::$_instance = new self(); 64 63 } 64 65 65 return self::$_instance; 66 66 } 67 67 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 } 88 88 89 89 /** … … 95 95 * @return array The array of default options. 96 96 */ 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] ] ); 101 101 } 102 102 … … 106 106 * @return array The cryptX options array with default values. 107 107 */ 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 ); 113 113 } 114 114 … … 120 120 * @return void 121 121 */ 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; 141 151 } 142 152 … … 148 158 * @return string The encrypted and linked content. 149 159 */ 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 tinyurl157 * 158 * @return image159 * /160 function cryptXtinyUrl() : void161 {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']; 163 173 $params = explode( '/', $url ); 164 174 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; 171 181 $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 ); 200 210 die; 201 211 } … … 214 224 * @return void 215 225 */ 216 function addPluginFilters( string $filterName): void 217 { 226 function addPluginFilters( string $filterName ): void { 218 227 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 ); 223 232 //add_filter($filterName, [$this,'autolink'], 11); 224 233 } 225 234 } 226 $this->addOtherFilters( $filterName);235 $this->addOtherFilters( $filterName ); 227 236 } 228 237 … … 236 245 * @return void 237 246 */ 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 ); 241 249 } 242 250 … … 252 260 * @return void 253 261 */ 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 ); 258 265 } 259 266 … … 265 272 * @return bool Returns true if the ID is excluded, false otherwise. 266 273 */ 267 function isIdExcluded( int $ID ): bool268 {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 ); 271 278 } 272 279 … … 279 286 * @param string $content The 280 287 */ 281 function replaceEmailInContent( string $content, bool $isShortcode =false): string {288 function replaceEmailInContent( string $content, bool $isShortcode = false ): string { 282 289 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 287 295 return $content; 288 296 } … … 295 303 * @return string The content with email addresses replaced with link text. 296 304 */ 297 function replaceEmailWithLinkText( string $content): string 298 { 305 function replaceEmailWithLinkText( string $content ): string { 299 306 $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 ); 301 309 } 302 310 … … 308 316 * @return string The encoded link text. 309 317 */ 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'] ) { 313 323 case 1: 314 324 $text = $this->getLinkText(); … … 319 329 case 3: 320 330 $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 ++; 323 333 break; 324 334 case 4: 325 $text = antispambot( $Match[1]);335 $text = antispambot( $Match[1] ); 326 336 break; 327 337 case 5: 328 $text = $this->getImageFromText( $Match);329 self::$imageCounter ++;338 $text = $this->getImageFromText( $Match ); 339 self::$imageCounter ++; 330 340 break; 331 341 default: 332 $text = $this->getDefaultLinkText( $Match);342 $text = $this->getDefaultLinkText( $Match ); 333 343 } 334 344 … … 343 353 * @return bool True if the match is in the whitelist, false otherwise. 344 354 */ 345 function in _white_list( array $Match): bool346 {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 ); 350 360 } 351 361 … … 364 374 * @return string The HTML image tag 365 375 */ 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'] ) . "\" />"; 369 378 } 370 379 … … 376 385 * @return string The HTML tag for the image. 377 386 */ 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'] ) . "\" />"; 381 389 } 382 390 … … 388 396 * @return string Returns the HTML image element. 389 397 */ 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] ) . "\" />"; 393 400 } 394 401 … … 404 411 * for each element. 405 412 */ 406 function getDefaultLinkText( array $Match ): string407 {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 ); 410 417 } 411 418 … … 419 426 * @return array An array of file names that match the filter. 420 427 */ 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 ); 424 430 $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 ) ) { 428 434 $directoryContent[] = $file; 429 435 } 430 436 } 437 431 438 return $directoryContent; 432 439 } … … 440 447 * @return string|null The content with encrypted email addresses, or null if $content is null. 441 448 */ 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 ); 455 463 } 456 464 … … 465 473 * @return string The search results with encrypted email addresses. 466 474 */ 467 function encryptEmailAddress( array $searchResults): string 468 { 475 function encryptEmailAddress( array $searchResults ): string { 469 476 $originalValue = $searchResults[0]; 470 477 471 if (strpos($searchResults[self::INDEX_TO_CHECK], '@') === self::NOT_FOUND) {478 if ( strpos( $searchResults[ self::INDEX_TO_CHECK ], '@' ) === self::NOT_FOUND ) { 472 479 return $originalValue; 473 480 } 474 481 475 $mailReference = self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK];482 $mailReference = self::MAIL_IDENTIFIER . $searchResults[ self::INDEX_TO_CHECK ]; 476 483 477 484 if ( str_starts_with( $searchResults[ self::INDEX_TO_CHECK ], self::SUBJECT_IDENTIFIER ) ) { … … 480 487 481 488 $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 ); 495 502 } 496 503 … … 506 513 * @return string The generated hash string. 507 514 */ 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 ++ ) { 514 520 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 ) { 518 524 $asciiValue = 128; 519 525 } 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 524 531 return $crypt; 525 532 } … … 535 542 * @return string The content with emails auto-linked. 536 543 */ 537 function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string 538 { 544 function addLinkToEmailAddresses( string $content, bool $shortcode = false ): string { 539 545 global $post; 540 546 $postID = is_object( $post ) ? $post->ID : - 1; … … 575 581 function installCryptX(): void { 576 582 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 ) { 583 589 $tmp[] = $exclude->post_id; 584 590 } 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 ); 588 594 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'] ) ) { 593 599 self::$cryptXOptions['c2i_font'] = CRYPTX_DIR_PATH . 'fonts/' . $firstFont[0]; 594 600 } 595 if ( empty(self::$cryptXOptions['c2i_fontSize'])) {601 if ( empty( self::$cryptXOptions['c2i_fontSize'] ) ) { 596 602 self::$cryptXOptions['c2i_fontSize'] = 10; 597 603 } 598 if ( empty(self::$cryptXOptions['c2i_fontRGB'])) {604 if ( empty( self::$cryptXOptions['c2i_fontRGB'] ) ) { 599 605 self::$cryptXOptions['c2i_fontRGB'] = '000000'; 600 606 } 601 update_option( 'cryptX', self::$cryptXOptions );607 update_option( 'cryptX', self::$cryptXOptions ); 602 608 self::$cryptXOptions = $this->loadCryptXOptionsWithDefaults(); // reread Options 603 609 } 604 610 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 ); 608 614 } else { 609 add_action( "dbx_{$hook_name}_sidebar", [$this, 'metaOptionFieldset' ]);615 add_action( "dbx_{$hook_name}_sidebar", [ $this, 'metaOptionFieldset' ] ); 610 616 } 611 617 } 612 618 613 619 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' ); 616 622 } 617 623 … … 622 628 * functionality for the current post or page. If the current post or page ID is excluded 623 629 **/ 624 function metaCheckbox(): void 625 { 630 function metaCheckbox(): void { 626 631 global $post; 627 632 ?> 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> 630 637 <?php 631 638 } … … 637 644 * @return void 638 645 */ 639 function metaOptionFieldset(): void 640 { 646 function metaOptionFieldset(): void { 641 647 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> 649 658 <?php 650 659 } … … 658 667 * @return void 659 668 */ 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 ); 665 674 } 666 675 … … 673 682 * @return array The updated excluded IDs list as an array, with the ID removed if it existed and added if necessary. 674 683 */ 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 ); 680 690 } 681 691 … … 688 698 * @return array The updated array of excluded IDs without the specified post ID. 689 699 */ 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 ] ); 694 704 break; 695 705 } 696 706 } 707 697 708 return $excludedIds; 698 709 } … … 706 717 * @return array The updated array of excluded IDs. 707 718 */ 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'] ) ) { 710 721 $excludedIds[] = $postId; 711 722 } 723 712 724 return $excludedIds; 713 725 } … … 720 732 * @return array The array of excluded IDs with duplicate values removed and sorted in ascending order. 721 733 */ 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 725 738 return $excludedIds; 726 739 } … … 734 747 * @return void 735 748 */ 736 function showMessage( $message, $errormsg = false): void {737 if ( $errormsg) {749 function showMessage( $message, $errormsg = false ): void { 750 if ( $errormsg ) { 738 751 echo '<div id="message" class="error">'; 739 } 740 else { 752 } else { 741 753 echo '<div id="message" class="updated fade">'; 742 754 } … … 751 763 */ 752 764 function getDomain(): string { 753 return $this->trimSlashFromDomain( $this->removeProtocolFromUrl($this->getSiteUrl()));765 return $this->trimSlashFromDomain( $this->removeProtocolFromUrl( $this->getSiteUrl() ) ); 754 766 } 755 767 … … 770 782 * @return string The URL string without the protocol. 771 783 */ 772 function removeProtocolFromUrl(string $url): string 773 { 784 function removeProtocolFromUrl( string $url ): string { 774 785 return preg_replace( '|https?://|', '', $url ); 775 786 } … … 782 793 * @return string The domain with the trailing slash removed. 783 794 */ 784 function trimSlashFromDomain(string $domain): string 785 { 795 function trimSlashFromDomain( string $domain ): string { 786 796 if ( $slashPosition = strpos( $domain, '/' ) ) { 787 797 $domain = substr( $domain, 0, $slashPosition ); 788 798 } 799 789 800 return $domain; 790 801 } … … 797 808 function loadJavascriptFiles(): void { 798 809 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' ); 800 811 } 801 812 … … 810 821 */ 811 822 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 } 820 839 } 821 840 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 '[' => '[', 856 ']' => ']', 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; 824 883 } 825 884 } -
cryptx/trunk/cryptx.php
r3102850 r3103107 4 4 * Plugin URI: http://weber-nrw.de/wordpress/cryptx/ 5 5 * 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. 46 * Version: 3.4.5 7 7 * Requires at least: 6.0 8 8 * Author: Ralf Weber … … 42 42 * @return string The encrypted content wrapped in the Cryptx shortcode. 43 43 */ 44 function encryptx( ?string $content, string $args = "" ): string { 45 return do_shortcode( '[cryptx]' . $content . '[/cryptx]' ); 44 function encryptx( ?string $content, ?array $args ): string { 45 $CryptX_instance = Cryptx\CryptX::getInstance(); 46 return do_shortcode( '[cryptx'. $CryptX_instance->convertArrayToArgumentString( $args ).']' . $content . '[/cryptx]' ); 46 47 } -
cryptx/trunk/readme.txt
r3102850 r3103107 5 5 Requires at least: 6.0 6 6 Tested up to: 6.5 7 Stable tag: 3.4. 47 Stable tag: 3.4.5 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later … … 22 22 23 23 == Changelog == 24 = 3.4.5 = 25 * The "encryptx" template function has been revised so that it accepts arguments again, as in previous versions. 24 26 = 3.4.4 = 25 27 * changed type hinting of an argument to be string or null on some methods
Note: See TracChangeset
for help on using the changeset viewer.