PluginProbe
CryptX / trunk
CryptX vtrunk
4.2.0 4.1.1 trunk 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.9 2.0 2.1 2.2 2.3 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 All 92 releases
← All changes | cryptx.php +350 -410 2.2trunk View file →
@@ -1,461 +1,401 @@
1 1 <?php
2 -/*
3 -Plugin Name: CryptX
4 -Plugin URI: http://weber-nrw.de/wordpress/cryptx/
5 -Description: No more SPAM by spiders scanning you site for email adresses. With CryptX you can hide all your email adresses, with and without a mailto-link, by converting them using javascript or UNICODE. Although you can choose to add a mailto-link to all unlinked email adresses with only one klick at the settings. That's great, isn't it?
6 -Version: 2.2
7 -Author: Ralf Weber
8 -Author URI: http://weber-nrw.de/
9 -*/
2 +/**
3 + * Plugin Name: CryptX
4 + * Plugin URI: https://wordpress.org/plugins/cryptx/
5 + * Description: CryptX encrypts email addresses in your posts, pages, comments, and text widgets to protect them from spam bots while keeping them readable for your visitors.
6 + * Version: 4.2.0
7 + * Requires at least: 6.7
8 + * Tested up to: 7.1
9 + * Requires PHP: 8.1
10 + * Author: Ralf Weber
11 + * Author URI: https://weber-nrw.de/
12 + * License: GPL v2 or later
13 + * License URI: https://www.gnu.org/licenses/gpl-2.0.html
14 + * Text Domain: cryptx
15 + *
16 + * CryptX is free software: you can redistribute it and/or modify
17 + * it under the terms of the GNU General Public License as published by
18 + * the Free Software Foundation, either version 2 of the License, or
19 + * any later version.
20 + *
21 + * CryptX is distributed in the hope that it will be useful,
22 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 + * GNU General Public License for more details.
25 + *
26 + * You should have received a copy of the GNU General Public License
27 + * along with CryptX. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
28 + *
29 + * @package CryptX
30 + * @since 1.0.0
31 + */
10 32
11 -/////////////////////////////////////////////////////////////////////////////
12 -
13 -/**
14 -* @internal prevent from direct calls
15 -*/
33 +// Prevent direct access
16 34 if (!defined('ABSPATH')) {
17 - return ;
18 - }
35 + exit;
36 +}
19 37
20 -/**
21 -* @internal prevent from second inclusion
22 -*/
23 -if (!class_exists('cryptX')) {
38 +// Plugin constants
39 +define('CRYPTX_VERSION', '4.2.0');
40 +define('CRYPTX_PLUGIN_FILE', __FILE__);
41 +define('CRYPTX_PLUGIN_BASENAME', plugin_basename(__FILE__));
42 +define('CRYPTX_BASENAME', plugin_basename(__FILE__)); // Add this missing constant
43 +define('CRYPTX_DIR_PATH', plugin_dir_path(__FILE__));
44 +define('CRYPTX_DIR_URL', plugin_dir_url(__FILE__));
45 +define('CRYPTX_BASEFOLDER', dirname(CRYPTX_PLUGIN_BASENAME));
24 46
25 -/////////////////////////////////////////////////////////////////////////////
47 +// Minimum requirements. Keep these in sync with the plugin header above and
48 +// with "Requires at least" / "Requires PHP" in readme.txt. They are defined
49 +// once and used both for the check and for the notice, so the number shown to
50 +// the user cannot drift away from the number actually enforced.
51 +define('CRYPTX_MIN_PHP', '8.1');
52 +define('CRYPTX_MIN_WP', '6.7');
26 53
27 -load_plugin_textdomain('cryptx', PLUGINDIR . '/' . dirname(plugin_basename (__FILE__)) . '/languages');
28 -
29 -$cryptX_var = (array) get_option('cryptX');
30 -
31 54 /**
32 -* "CryptX" WordPress Plugin
33 -*
34 -* @author Ralf Weber <ralf@weber-nrw.de>
35 -* @license http://opensource.org/licenses/gpl-license.php GNU Public License
36 -*/
37 -Class cryptX {
55 + * Shows an admin notice to whoever is in a position to act on it.
56 + *
57 + * Registered on both admin_notices and network_admin_notices. Without the
58 + * second, a network administrator working in the network backend -- the only
59 + * person who can deactivate a network-activated plugin -- never saw that the
60 + * server runs too old a PHP, or that a class file is missing. The capability
61 + * differs per screen: on a site it is activate_plugins, in the network backend
62 + * manage_network_plugins, which a mere site administrator does not hold.
63 + *
64 + * @param string $message The message, already translated and unescaped.
65 + *
66 + * @return void
67 + */
68 +function cryptx_admin_notice(string $message): void
69 +{
70 + $render = static function () use ($message): void {
71 + $capability = is_network_admin() ? 'manage_network_plugins' : 'activate_plugins';
38 72
39 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
73 + if (!current_user_can($capability)) {
74 + return;
75 + }
40 76
41 - /**
42 - * Constructor
43 - *
44 - * This constructor attaches the needer plugin hook callbacks
45 - */
46 - function cryptX() {
77 + printf('<div class="notice notice-error"><p>%s</p></div>', esc_html($message));
78 + };
47 79
48 - global $cryptX_var;
80 + add_action('admin_notices', $render);
81 + add_action('network_admin_notices', $render);
82 +}
49 83
50 - // attach the converstion handlers
51 - //
52 - if (@$cryptX_var[theContent]) {
53 - $this->_filter('the_content');
54 - }
55 - if (@$cryptX_var[theExcerpt]) {
56 - $this->_filter('the_excerpt');
57 - }
58 - if (@$cryptX_var[commentText]) {
59 - $this->_filter('comment_text');
60 - }
84 +if (version_compare(PHP_VERSION, CRYPTX_MIN_PHP, '<')) {
85 + cryptx_admin_notice(sprintf(
86 + /* translators: %1$s: Required PHP version, %2$s: Current PHP version */
87 + __('CryptX requires PHP version %1$s or higher. You are running version %2$s. Please update PHP.', 'cryptx'),
88 + CRYPTX_MIN_PHP,
89 + PHP_VERSION
90 + ));
91 + return;
92 +}
61 93
62 - // attach to admin menu
63 - //
64 - if (is_admin()) {
65 - add_action('admin_menu',
66 - array(&$this, '_menu')
67 - );
68 - }
94 +// WordPress version check
95 +global $wp_version;
96 +if (version_compare($wp_version, CRYPTX_MIN_WP, '<')) {
97 + cryptx_admin_notice(sprintf(
98 + /* translators: %1$s: Required WordPress version, %2$s: Current WordPress version */
99 + __('CryptX requires WordPress version %1$s or higher. You are running version %2$s. Please update WordPress.', 'cryptx'),
100 + CRYPTX_MIN_WP,
101 + $GLOBALS['wp_version']
102 + ));
103 + return;
104 +}
69 105
70 - // attach to plugin installation
71 - //
72 - add_action(
73 - 'activate_' . str_replace(
74 - DIRECTORY_SEPARATOR, '/',
75 - str_replace(
76 - realpath(ABSPATH . PLUGINDIR) . DIRECTORY_SEPARATOR,
77 - '', __FILE__
78 - )
79 - ),
80 - array(&$this, '_install')
81 - );
106 +// Autoloader for plugin classes
107 +spl_autoload_register(function ($class) {
108 + // Check if the class belongs to our namespace
109 + if (strpos($class, 'CryptX\\') !== 0) {
110 + return;
111 + }
82 112
83 - // attach javascript to Header
84 - //
85 - if (@$cryptX_var[java]) {
86 - add_action(
87 - 'wp_head',
88 - array(&$this, '_header')
89 - );
90 - }
113 + // Remove namespace prefix
114 + $class = substr($class, 7);
91 115
92 - } // End function
116 + // Convert namespace separators to directory separators
117 + $class = str_replace('\\', DIRECTORY_SEPARATOR, $class);
93 118
94 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
119 + // Build the full path
120 + $file = CRYPTX_DIR_PATH . 'classes' . DIRECTORY_SEPARATOR . $class . '.php';
95 121
96 - function _filter($apply)
97 - {
98 - global $cryptX_var;
122 + // Include the file if it exists
123 + if (file_exists($file)) {
124 + require_once $file;
125 + }
126 +});
99 127
100 - if (@$cryptX_var[autolink]) {
101 - add_filter($apply,
102 - array(&$this, '_autolink'),
103 - 9);
104 - }
105 - if (@$cryptX_var[java]) {
106 - add_filter($apply,
107 - array(&$this, '_encrypt'),
108 - 11);
109 - } else {
110 - add_filter($apply,
111 - array(&$this, '_unicode'),
112 - 11);
113 - }
128 +// The settings screen posts nothing: it talks to the REST routes in
129 +// CryptX\Admin\RestController, which carry their own capability check and are
130 +// covered by WordPress' REST nonce. The global cryptx_nonce_check() that used
131 +// to sit here guarded $_POST['cryptX_var'], a key nothing has sent since the
132 +// old settings form was removed in 4.1.0 -- a dead guard next to a live one is
133 +// a trap for whoever wires up the next form.
114 134
115 - }
135 +// Initialize the plugin
136 +add_action('plugins_loaded', function() {
137 + // Check if all required classes can be loaded
138 + $requiredClasses = [
139 + 'CryptX\\CryptX',
140 + 'CryptX\\Config',
141 + 'CryptX\\SecureEncryption',
142 + 'CryptX\\Exposure',
143 + 'CryptX\\Block',
144 + 'CryptX\\ImageToken',
145 + 'CryptX\\Admin\\NetworkDefaults',
146 + 'CryptX\\Admin\\SettingsPage',
147 + 'CryptX\\Admin\\SettingsSchema',
148 + 'CryptX\\Admin\\RestController',
149 + 'CryptX\\Admin\\SiteHealth',
150 + ];
116 151
117 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
152 + $missingClasses = [];
153 + foreach ($requiredClasses as $class) {
154 + if (!class_exists($class)) {
155 + $missingClasses[] = $class;
156 + }
157 + }
118 158
119 - function _linktext($txt)
120 - {
121 - global $cryptX_var;
159 + if (!empty($missingClasses)) {
160 + cryptx_admin_notice(
161 + __('CryptX: Missing required classes: ', 'cryptx') . implode(', ', $missingClasses)
162 + );
163 + return;
164 + }
122 165
123 - switch ($cryptX_var[opt_linktext]) {
166 + // Initialize the main plugin class
167 + try {
168 + $cryptx_instance = CryptX\CryptX::get_instance();
169 + $cryptx_instance->startCryptX();
170 + cryptx_register_action_links();
124 171
125 - case 1: // alternative text for mail link
126 - $linktext = $cryptX_var[alt_linktext];
127 - break;
172 + // Guarded here as well as inside register(), and deliberately not
173 + // listed in $requiredClasses above. Both of those would load the file
174 + // on every single front-end and admin request -- class_exists() runs
175 + // the autoloader, and so does a static call -- to register commands
176 + // that only exist under WP-CLI.
177 + //
178 + // class_exists() is still asked so that a package missing the file
179 + // cannot raise a fatal Error, which catch (Exception) below would not
180 + // have caught. It buys no notice: the commands are then simply absent.
181 + // That is the right silence -- nothing a visitor or an administrator
182 + // sees depends on them.
183 + if (defined('WP_CLI') && WP_CLI && class_exists('CryptX\Cli')) {
184 + CryptX\Cli::register();
185 + }
186 + } catch (Exception $e) {
187 + cryptx_admin_notice(
188 + __('CryptX initialization failed: ', 'cryptx') . $e->getMessage()
189 + );
190 + }
191 +});
128 192
129 - case 2: // alternative image for mail link
130 - $linktext = "<img src=\"" . $cryptX_var[alt_linkimage] . "\" class=\"cryptxImage\" alt=\"" . $cryptX_var[alt_linkimage_title] . "\" title=\"" . $cryptX_var[alt_linkimage_title] . "\">";
131 - break;
193 +/**
194 + * Runs a callback once for every site of the network, in batches.
195 + *
196 + * get_sites() without a limit pulls the whole network into memory, and a
197 + * network can have thousands of sites. Same construction as uninstall.php,
198 + * deliberately: the two do the same job at opposite ends of the plugin's life,
199 + * and one of them being cleverer than the other only makes both harder to
200 + * trust.
201 + *
202 + * On a single site the callback simply runs once.
203 + *
204 + * @param callable $callback Receives nothing; runs with the site switched in.
205 + *
206 + * @return void
207 + */
208 +function cryptx_for_each_site(callable $callback): void
209 +{
210 + if (!is_multisite()) {
211 + $callback();
132 212
133 - case 3: // uploaded image for mail link
134 - $imgurl = "/" . PLUGINDIR . "/" . dirname(plugin_basename (__FILE__)) . "/images/" . $cryptX_var[alt_uploadedimage];
135 - $linktext = "<img src=\"" . $imgurl . "\" class=\"cryptxImage\" alt=\"" . $cryptX_var[http_linkimage_title] . "\" title=\"" . $cryptX_var[http_linkimage_title] . "\">";
136 - break;
213 + return;
214 + }
137 215
138 - case 4: // text scrambled by antispambot
139 - $linktext = antispambot($txt);
140 - break;
216 + $batch_size = 100;
217 + $offset = 0;
141 218
142 - default:
143 - $linktext = str_replace( "@", $cryptX_var[at], $txt);
144 - $linktext = str_replace( ".", $cryptX_var[dot], $linktext);
219 + do {
220 + $site_ids = get_sites([
221 + 'fields' => 'ids',
222 + 'number' => $batch_size,
223 + 'offset' => $offset,
224 + 'orderby' => 'id',
225 + 'update_site_meta_cache' => false,
226 + ]);
145 227
146 - }
228 + foreach ($site_ids as $site_id) {
229 + switch_to_blog($site_id);
147 230
148 - return $linktext;
149 - }
231 + // finally, so a failing callback does not leave the blog stack
232 + // switched for whatever runs next. It does not keep the loop
233 + // going: an exception still travels upwards and the remaining
234 + // sites are skipped. Catching it here would hide a broken site
235 + // instead, and that is a trade to make deliberately, not in
236 + // passing.
237 + try {
238 + $callback();
239 + } finally {
240 + restore_current_blog();
241 + }
242 + }
150 243
151 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
244 + $offset += $batch_size;
245 + } while (count($site_ids) === $batch_size);
246 +}
152 247
153 - function _dirImages()
154 - {
155 - $dir = $_SERVER["DOCUMENT_ROOT"].'/'.PLUGINDIR.'/'.dirname(plugin_basename (__FILE__)).'/images';
156 - $fh = opendir($dir); //Verzeichnis
157 - echo "<!-- ".$fh." -->";
158 - $verzeichnisinhalt = array();
159 - while (true == ($file = readdir($fh)))
160 - {
161 - echo "<!-- ".$file." -->";
162 - if ((substr(strtolower($file), -3)=="jpg") or (substr(strtolower($file), -3)=="gif")) //Abfrage nach g�ltigen Datenformat
163 - {
164 - $verzeichnisinhalt[] = $file;
165 - }
166 - }
167 - return $verzeichnisinhalt;
168 - }
248 +/**
249 + * Removes the plugin's transients from the site that is currently switched in.
250 + *
251 + * @return void
252 + */
253 +function cryptx_delete_transients(): void
254 +{
255 + global $wpdb;
169 256
170 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
257 + // The LIKE patterns run through $wpdb->esc_like() and $wpdb->prepare().
258 + // No user input is involved here, so this is not a hole, but "_" is a
259 + // single-character wildcard in LIKE: unescaped, '_transient_cryptx_%' also
260 + // matches names like 'Xtransient1cryptxZ...' belonging to other plugins.
261 + // esc_like() turns those underscores into literal ones. The table name is
262 + // an identifier, not a value, and therefore must stay outside prepare().
263 + $transientLike = $wpdb->esc_like('_transient_cryptx_') . '%';
264 + $transientTimeoutLike = $wpdb->esc_like('_transient_timeout_cryptx_') . '%';
171 265
172 - function _encrypt($content)
173 - {
174 - global $cryptX_var;
266 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
267 + $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $transientLike));
268 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
269 + $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $transientTimeoutLike));
270 +}
175 271
176 - preg_match_all('/<a (.*?)(href=("|\')(.*?)("|\')(.*?)|)>(.*?)<\/a>/i', $content, $links, PREG_SET_ORDER);
272 +/**
273 + * Sets up the plugin's options for the site that is currently switched in.
274 + *
275 + * @return void
276 + */
277 +function cryptx_install_site(): void
278 +{
279 + if (!class_exists('CryptX\\CryptX')) {
280 + return;
281 + }
177 282
178 - foreach( $links as $link ) {
283 + CryptX\CryptX::get_instance()->installCryptX();
284 +}
179 285
180 - if(preg_match('/mailto:(.*)/', $link[4], $mail)) {
181 - $crypt = '';
182 - $ascii = 0;
183 - for ($i = 0; $i < strlen( $mail[1] ); $i++) {
184 - $ascii = ord ( substr ( $mail[1], $i ) );
185 - if (8364 <= $char) {
186 - $ascii = 128;
187 - }
188 - $crypt .= chr($ascii + 1);
189 - }
190 - $content = str_replace( $link[4], "javascript:DeCryptX('" . $crypt . "')", $content);
191 - $content = str_replace( $link[7], $this->_linktext($link[7]), $content);
192 - }
286 +// Activation.
287 +//
288 +// $network_wide is true when someone ticks "Network Activate". WordPress then
289 +// fires this hook exactly once, not once per site -- so without the loop, every
290 +// site but the current one is left without its stored options and, more to the
291 +// point, without the one-time migration of the pre-4.0 "cryptxoff" post meta.
292 +// The plugin still works there, because the defaults fill in, but a site that
293 +// carried excluded posts from an old version would silently lose them.
294 +register_activation_hook(__FILE__, function ($network_wide = false) {
295 + if ($network_wide) {
296 + cryptx_for_each_site('cryptx_install_site');
297 + } else {
298 + cryptx_install_site();
299 + }
193 300
194 - } // foreach
301 + flush_rewrite_rules();
302 +});
195 303
304 +// Deactivation. Same reason, other direction: the transients of every site but
305 +// the current one used to survive a network deactivation.
306 +register_deactivation_hook(__FILE__, function ($network_wide = false) {
307 + if ($network_wide) {
308 + cryptx_for_each_site('cryptx_delete_transients');
309 + } else {
310 + cryptx_delete_transients();
311 + }
312 +});
196 313
197 - return $content;
198 - }
314 +// A site created while the plugin is network-active gets the same treatment as
315 +// one that existed at activation time. Without this the new site works -- the
316 +// defaults see to that -- but nothing is ever written until someone saves, and
317 +// the behaviour differs from every other site in the network for no reason
318 +// anybody could see.
319 +add_action('wp_initialize_site', function ($site) {
320 + // The network option directly, not is_plugin_active_for_network(): that
321 + // lives in wp-admin/includes/plugin.php, which is not loaded when a site is
322 + // created over the REST API or WP-CLI -- exactly the paths that create sites
323 + // in bulk.
324 + $network_active = get_site_option('active_sitewide_plugins', []);
199 325
200 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
326 + if (!isset($network_active[CRYPTX_PLUGIN_BASENAME])) {
327 + return;
328 + }
201 329
202 - function _unicode($content)
203 - {
204 - global $cryptX_var;
330 + $site_id = is_object($site) ? (int) $site->blog_id : (int) $site;
205 331
206 - preg_match_all('/<a (.*?)(href=("|\')(.*?)("|\')(.*?)|)>(.*?)<\/a>/i', $content, $links, PREG_SET_ORDER);
332 + switch_to_blog($site_id);
333 + cryptx_install_site();
334 + restore_current_blog();
335 +}, 20);
207 336
208 - foreach( $links as $link ) {
337 +// Add plugin action links.
338 +//
339 +// Registered inside the successful-initialisation path on purpose, not at the
340 +// top level of this file. It refers to a class constant, and the plugins screen
341 +// is exactly where someone goes to switch off a plugin whose class files are
342 +// missing -- a fatal error there would take away the only lever they have.
343 +// A plugin that did not initialise has no settings page to link to anyway.
344 +function cryptx_register_action_links(): void
345 +{
346 + add_filter('plugin_action_links_' . CRYPTX_PLUGIN_BASENAME, function ($links) {
347 + $settings_link = '<a href="' .
348 + esc_url(admin_url('options-general.php?page=' . CryptX\Admin\SettingsPage::MENU_SLUG)) .
349 + '">' . esc_html__('Settings', 'cryptx') . '</a>';
350 + array_unshift($links, $settings_link);
209 351
210 - if(preg_match('/mailto:(.*)/', $link[4], $mail)) {
211 - $mailto = "mailto:" . $mail[1];
212 - $content = str_replace( $mailto, antispambot($mailto), $content);
213 - $content = str_replace( $link[7], $this->_linktext($link[7]), $content);
214 - }
352 + return $links;
353 + });
354 +}
215 355
216 - } // foreach
217 - return $content;
218 - }
356 +/**
357 + * Encrypts the given content using the CryptX library and wraps it with a shortcode.
358 + *
359 + * @param string $content The content to be encrypted.
360 + * @param array|null $args Optional arguments to customize the encryption process.
361 + *
362 + * @return string The encrypted content wrapped in the appropriate shortcode.
363 + */
364 +if (!function_exists('cryptx_encrypt')) {
365 + function cryptx_encrypt(string $content, ?array $args = []): string
366 + {
367 + $cryptXInstance = Cryptx\CryptX::get_instance();
368 + // $attributesString contains the escaped (esc_attr()) shortcode attributes from $args
369 + // The signature allows null, convertArrayToArgumentString() does not.
370 + $attributesString = $cryptXInstance->convertArrayToArgumentString($args ?? []);
219 371
220 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
372 + // wp_kses_post() and not esc_html(): the caller passes content, and
373 + // content in WordPress may carry markup. esc_html() turned a "<br>" in
374 + // a theme field into a visible "&lt;br&gt;" -- reported in the support
375 + // forum, and worked around there with html_entity_decode(), which
376 + // undoes the plugin's own protection in the Unicode and entity modes.
377 + // wp_kses_post keeps what a post may contain and drops the rest.
378 + $shortcode = '[cryptx' . $attributesString . ']' . wp_kses_post($content) . '[/cryptx]';
221 379
222 - function _autolink($content) {
223 -
224 - $src[]="/([\s])([_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,}))/si";
225 - $src[]="/(>)([_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,}))(<)/si";
226 - $src[]="/^([_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,}))/si";
227 - $src[]="/(<a[^>]*>)<a[^>]*>/";
228 - $src[]="/(<\/A>)<\/A>/i";
229 -
230 - $tar[]="\\1<a href=\"mailto:\\2\">\\2</a>";
231 - $tar[]="\\1<a href=\"mailto:\\2\">\\2</a>\\6";
232 - $tar[]="<a href=\"mailto:\\0\">\\0</a>";
233 - $tar[]="\\1";
234 - $tar[]="\\1";
235 -
236 - $content = preg_replace($src,$tar,$content);
237 -
238 - return $content;
239 - }
240 -
241 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
242 -
243 -
244 - function _install() {
245 - add_option(
246 - 'cryptX',
247 - array(
248 - 'at' => ' [at] ',
249 - 'dot' => ' [dot] ',
250 - 'theContent' => 1,
251 - 'theExcerpt' => 0,
252 - 'commentText' => 1,
253 - 'java' => 1,
254 - 'opt_linktext' => 0,
255 - )
256 - );
257 - }
258 -
259 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
260 -
261 - /**
262 - * Attach the menu page to the `Options` tab
263 - */
264 - function _header()
265 - {
266 - $cryptX_script.= "<script type=\"text/javascript\" src=\"" . get_option('siteurl') . '/' . PLUGINDIR . '/' . dirname(plugin_basename (__FILE__)) . "/js/cryptx.js\"></script>\n";
267 - print($cryptX_script);
268 - }
269 -
270 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
271 -
272 - /**
273 - * Attach the menu page to the `Options` tab
274 - */
275 - function _menu() {
276 - add_options_page(
277 - 'CryptX',
278 - (version_compare($GLOBALS['wp_version'], '2.6.999', '>') ? '<img src="' .@plugins_url('cryptx/icon.png'). '" width="10" height="10" alt="CryptX Icon" />' : ''). 'CryptX',
279 - 9,
280 - __FILE__,
281 - array(
282 - $this,
283 - '_submenu'
284 - )
285 - );
286 - }
287 -
288 - /**
289 - * Handles and renders the menu page
290 - */
291 - function _submenu() {
292 - global $cryptX_var;
293 -
294 - if (isset($_POST) && !empty($_POST)) {
295 - if (function_exists('current_user_can') === true && (current_user_can('manage_options') === false || current_user_can('edit_plugins') === false)) {
296 - wp_die("You don't have permission to access!");
297 - }
298 - check_admin_referer('cryptX');
299 - update_option( 'cryptX', $_POST['cryptX_var']);
300 - $cryptX_var = (array) get_option('cryptX'); // reread Options
301 - ?>
302 - <div id="message" class="updated fade">
303 - <p><strong><?php _e('Settings saved.') ?></strong></p>
304 - </div>
305 - <?php } ?>
306 -
307 - <div class="wrap">
308 - <?php if (version_compare($GLOBALS['wp_version'], '2.6.999', '>')) { ?>
309 - <div class="icon32" style="background: url(<?php echo @plugins_url('cryptx/icon32.png') ?>) no-repeat"><br /></div>
310 - <?php } ?>
311 - <h2>CryptX</h2>
312 -
313 - <form method="post" action="">
314 -
315 - <?php wp_nonce_field('cryptX') ?>
316 -
317 - <div id="poststuff" class="ui-sortable">
318 - <div id="wp_seo_about_wpseo" class="postbox">
319 -
320 - <h3><?php _e("Presentation",'cryptx'); ?></h3>
321 -
322 - <div class="inside">
323 - <table class="form-table">
324 - <tr valign="top">
325 - <td><input name="cryptX_var[opt_linktext]" type="radio" id="opt_linktext" value="0" <?php echo ($cryptX_var[opt_linktext] == 0) ? 'checked="checked"' : ''; ?> /></td>
326 - <th scope="row"><label for="cryptX_var[at]"><?php _e("Replacement for '@'",'cryptx'); ?></label></th>
327 - <td><input name="cryptX_var[at]" value="<?php echo $cryptX_var[at]; ?>" type="text" class="regular-text" /></td>
328 - </tr>
329 - <tr valign="top">
330 - <td>&nbsp;</td>
331 - <th scope="row"><label for="cryptX_var[dot]"><?php _e("Replacement for '.'",'cryptx'); ?></label></th>
332 - <td><input name="cryptX_var[dot]" value="<?php echo $cryptX_var[dot]; ?>" type="text" class="regular-text" /></td>
333 - </tr>
334 - <tr valign="top">
335 - <td scope="row"><input type="radio" name="cryptX_var[opt_linktext]" id="opt_linktext2" value="1" <?php echo ($cryptX_var[opt_linktext] == 1) ? 'checked="checked"' : ''; ?>/></td>
336 - <th><label for="cryptX_var[alt_linktext]"><?php _e("Text for link",'cryptx'); ?></label></th>
337 - <td><input name="cryptX_var[alt_linktext]" value="<?php echo $cryptX_var[alt_linktext]; ?>" type="text" class="regular-text" /></td>
338 - </tr>
339 - <tr valign="top">
340 - <td scope="row"><input type="radio" name="cryptX_var[opt_linktext]" id="opt_linktext3" value="2" <?php echo ($cryptX_var[opt_linktext] == 2) ? 'checked="checked"' : ''; ?>/></td>
341 - <th><label for="cryptX_var[alt_linkimage]"><?php _e("Image-URL",'cryptx'); ?></label></th>
342 - <td><input name="cryptX_var[alt_linkimage]" value="<?php echo $cryptX_var[alt_linkimage]; ?>" type="text" class="regular-text" /></td>
343 - </tr>
344 - <tr valign="top">
345 - <td scope="row">&nbsp;</td>
346 - <th><label for="cryptX_var[http_linkimage_title]"><?php _e("Title-Tag for the Image",'cryptx'); ?></label></th>
347 - <td><input name="cryptX_var[http_linkimage_title]" value="<?php echo $cryptX_var[http_linkimage_title]; ?>" type="text" class="regular-text" /></td>
348 - </tr>
349 - <tr valign="top">
350 - <td scope="row"><input type="radio" name="cryptX_var[opt_linktext]" id="opt_linktext4" value="3" <?php echo ($cryptX_var[opt_linktext] == 3) ? 'checked="checked"' : ''; ?>/></td>
351 - <th><label for="cryptX_var[alt_uploadedimage]"><?php _e("Select image from folder",'cryptx'); ?></label></th>
352 - <td><select name="cryptX_var[alt_uploadedimage]" onchange="cryptX_bild_wechsel(this)">
353 - <?php foreach($this->_dirImages() as $image) {
354 - $FirstIMG = (!isset($FirstIMG))? plugins_url('cryptx/images/').$image : ($cryptX_var[alt_uploadedimage] == plugins_url('cryptx/images/').$image) ? plugins_url('cryptx/images/').$image : $FirstIMG;
355 - ?>
356 - <option value="<?php echo plugins_url('cryptx/images/').$image; ?>" <?php echo ($cryptX_var[alt_uploadedimage] == plugins_url('cryptx/images/').$image) ? 'selected' : ''; ?> ><?php echo $image; ?></option>
357 - <?php } ?>
358 - </select>&nbsp;&nbsp;<img src="<?php echo $FirstIMG; ?>" id="cryptXmailTo"></td>
359 - </tr>
360 - <tr valign="top">
361 - <td>&nbsp;</td>
362 - <th><label for="cryptX_var[alt_linkimage_title]"><?php _e("Title-Tag for the Image",'cryptx'); ?></label></th>
363 - <td><input name="cryptX_var[alt_linkimage_title]" value="<?php echo $cryptX_var[alt_linkimage_title]; ?>" type="text" class="regular-text" />
364 - <span class="setting-description"><?php _e("Upload your favorite email-image to ../plugins/cryptx/images. Only .jpg and .gif Supported!",'cryptx'); ?></span></td>
365 - </tr>
366 - <tr valign="top">
367 - <td scope="row"><input type="radio" name="cryptX_var[opt_linktext]" id="opt_linktext" value="4" <?php echo ($cryptX_var[opt_linktext] == 4) ? 'checked="checked"' : ''; ?>/></td>
368 - <th colspan="2"><?php _e("Text scrambled by AntiSpamBot (<small>Try it and look at your site and check the html source!</small>)",'cryptx'); ?></th>
369 - </tr>
370 - </table>
371 - </div>
372 - </div>
373 -
374 - <div id="wp_seo_about_wpseo" class="postbox">
375 -
376 - <h3><?php _e("General",'cryptx'); ?></h3>
377 -
378 - <div class="inside">
379 - <table class="form-table">
380 - <tr valign="top">
381 - <th scope="row"><?php _e("Apply CryptX to...",'cryptx'); ?></th>
382 - <td><input name="cryptX_var[theContent]" <?php echo ($cryptX_var[theContent]) ? 'checked="checked"' : ''; ?> type="checkbox" />&nbsp;&nbsp;<?php _e("Content",'cryptx'); ?><br/>
383 - <input name="cryptX_var[theExcerpt]" <?php echo ($cryptX_var[theExcerpt]) ? 'checked="checked"' : ''; ?> type="checkbox" />&nbsp;&nbsp;<?php _e("Excerpt",'cryptx'); ?><br/>
384 - <input name="cryptX_var[commentText]" <?php echo ($cryptX_var[commentText]) ? 'checked="checked"' : ''; ?> type="checkbox" />&nbsp;&nbsp;<?php _e("Comments",'cryptx'); ?></td>
385 - </tr>
386 - <tr valign="top">
387 - <th scope="row"><?php _e("Type of decryption",'cryptx'); ?></th>
388 - <td><input name="cryptX_var[java]" <?php echo ($cryptX_var[java]) ? 'checked="checked"' : ''; ?> type="radio" value="1" />&nbsp;&nbsp;<?php _e("Use javascript to hide the Email-Link.",'cryptx'); ?><br/>
389 - <input name="cryptX_var[java]" <?php echo (!$cryptX_var[java]) ? 'checked="checked"' : ''; ?> type="radio" value="0" />&nbsp;&nbsp;<?php _e("Use Unicode to hide the Email-Link.",'cryptx'); ?></td>
390 - </tr>
391 - <tr valign="top">
392 - <th scope="row" colspan="2"><input name="cryptX_var[autolink]" <?php echo ($cryptX_var[autolink]) ? 'checked="checked"' : ''; ?> type="checkbox" />&nbsp;&nbsp;<?php _e("Add mailto to all unlinked email addresses",'cryptx'); ?></th>
393 - </tr>
394 - </table>
395 -
396 - </div>
397 - </div>
398 - <p><input type="submit" name="cryptX" class="button-primary" value="<?php _e('Save Changes') ?>" /></p>
399 - </div>
400 -
401 - </form>
402 -
403 - <script type="text/javascript">
404 - <!--
405 - function cryptX_bild_wechsel(select){
406 - document.getElementById("cryptXmailTo").src = select.options[select.options.selectedIndex].value;
407 - return true;
408 - } //-->
409 - </script>
410 -
411 - </div>
412 -<?php
413 - }
414 -
415 - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
416 -
417 -
418 - //--end-of-class
419 - }
420 -
380 + return do_shortcode($shortcode);
381 + }
421 382 }
422 383
423 -/////////////////////////////////////////////////////////////////////////////
424 -
425 384 /**
426 -* Initiating the plugin...
427 -* @see cryptX
428 -*/
429 -new cryptX;
385 + * Encrypts the given content using the CryptX library and wraps it with a shortcode.
386 + *
387 + * @deprecated 4.0.5 Use cryptx_encrypt() instead.
388 + * @see cryptx_encrypt()
389 + */
390 +if (!function_exists('encryptx')) {
391 + function encryptx(string $content, ?array $args = []): string
392 + {
393 + _doing_it_wrong(
394 + 'encryptx',
395 + esc_html__('This function is deprecated. Use cryptx_encrypt() instead.', 'cryptx'),
396 + '4.0.5'
397 + );
430 398
431 -/**
432 -* Create Template functions...
433 -* $content = string to convert
434 -* $text = string to replace linktext
435 -* $echo = 0: keep result in a variable, 1: show result
436 -*/
437 -function cryptx( $content, $text="", $css="", $echo=1 )
438 -{
439 - global $cryptX_var;
440 -
441 - $cryptX = new cryptX;
442 -
443 - $content = $cryptX->_autolink( $content );
444 -
445 - if(@$cryptX_var[java]) {
446 - $content = $cryptX->_encrypt( $content );
447 - } else {
448 - $content = $cryptX->_unicode( $content );
449 - }
450 -
451 - if("" != $text) {
452 - $content = preg_replace( "/(<a[^>]*>)(.*)(<\/a>)/i", '$1'.$text.'$3', $content );
453 - }
454 - if("" != $css) {
455 - $content = preg_replace( "/(<a[^>]*)(>)/i", '$1 class="'.$css.'"$2', $content );
456 - }
457 - if(1 == $echo) echo $content;
458 -
459 - return $content;
460 -}
461 -?>
399 + return cryptx_encrypt($content, $args);
400 + }
401 +}