PluginProbe ʕ •ᴥ•ʔ
PiWeb Product Enquiry or product catalog for WooCommerce / 2.2.34.6
PiWeb Product Enquiry or product catalog for WooCommerce v2.2.34.6
2.2.34.43 2.2.34.42 2.2.34.41 2.2.34.40 2.2.34.39 trunk 2.2.22 2.2.26 2.2.33.16 2.2.33.17 2.2.33.19 2.2.33.20 2.2.33.21 2.2.33.22 2.2.33.23 2.2.33.24 2.2.33.26 2.2.33.27 2.2.33.29 2.2.33.30 2.2.33.31 2.2.33.32 2.2.33.33 2.2.33.34 2.2.33.36 2.2.33.37 2.2.33.39 2.2.33.40 2.2.33.41 2.2.33.42 2.2.33.43 2.2.33.44 2.2.33.46 2.2.33.47 2.2.33.49 2.2.34.0 2.2.34.1 2.2.34.10 2.2.34.11 2.2.34.12 2.2.34.13 2.2.34.14 2.2.34.16 2.2.34.17 2.2.34.19 2.2.34.2 2.2.34.20 2.2.34.21 2.2.34.22 2.2.34.23 2.2.34.24 2.2.34.26 2.2.34.27 2.2.34.29 2.2.34.3 2.2.34.30 2.2.34.31 2.2.34.32 2.2.34.33 2.2.34.34 2.2.34.36 2.2.34.37 2.2.34.4 2.2.34.6 2.2.34.7 2.2.34.9
enquiry-quotation-for-woocommerce / includes / class-php-captcha.php
enquiry-quotation-for-woocommerce / includes Last commit date
img 1 year ago ARIAL.TTF 1 year ago background.png 1 year ago banner-sample.php 1 year ago class-php-captcha.php 1 year ago class-pisol-enquiry-quotation-woocommerce-activator.php 1 year ago class-pisol-enquiry-quotation-woocommerce-deactivator.php 1 year ago class-pisol-enquiry-quotation-woocommerce-i18n.php 1 year ago class-pisol-enquiry-quotation-woocommerce-loader.php 1 year ago class-pisol-enquiry-quotation-woocommerce.php 1 year ago conflict-fixer.php 1 year ago includes.php 1 year ago index.php 1 year ago pisol.class.form.php 1 year ago pisol.class.promotion.php 1 year ago review-icon.svg 1 year ago review.php 1 year ago
class-php-captcha.php
398 lines
1 <?php
2
3 class PISOL_ENQ_CaptchaGenerator{
4
5 static $instance = null;
6
7 private $useGD = false;
8
9 private $width = 200;
10
11 private $height = 50;
12
13 private $fontPath = '';
14
15 private $captchaLength = 6;
16
17 static function get_instance() {
18 if ( is_null( self::$instance ) ) {
19 self::$instance = new self();
20 }
21 return self::$instance;
22 }
23
24 public function __construct() {
25
26
27 if(! self::captcha_enabled() ) return;
28
29 if (extension_loaded('gd')) {
30 $this->useGD = 'gd';
31 } elseif (extension_loaded('imagick')) {
32 $this->useGD = 'imagick';
33 }
34
35 if($this->useGD === false) {
36 add_action( 'admin_notices', function(){
37 ?>
38 <div class="error notice">
39 <p><?php esc_html_e( 'Image generation module not installed in your server, make sure to install GD or Imagick library for PHP to use Captcha for checkout page', 'pi-dcw' ); ?></p>
40 </div>
41 <?php
42 } );
43 return;
44 }
45
46 $this->fontPath = __DIR__.'/ARIAL.TTF';
47
48 $this->captchaLength = $this->get_captcha_length();
49
50 $this->width = $this->captcha_width();
51
52
53 add_action('pi_eqw_add_captcha_field', [$this, 'custom_checkout_captcha_field']);
54
55 add_action('wc_ajax_pi_enq_generate_captcha', [$this, 'send_generated_captcha_image']);
56 add_action('wc_ajax_pi_enq_refresh_captcha', [$this, 'refreshCaptcha']);
57
58 add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']);
59
60 }
61
62
63 public function custom_checkout_captcha_field() {
64
65 $placeholder = $this->get_captcha_placeholder();
66 $refresh_title = $this->get_refresh_captcha_title();
67
68 echo '<div id="pi_enq_captcha_container">';
69 echo '<div id="pi_enq_captcha">';
70 echo '<input type="text" name="captcha_field" id="captcha_field" class="input-text" required placeholder="'.esc_attr($placeholder).'">';
71 echo '<div class="captcha_image_container">';
72 echo '<img src="' . esc_url( site_url('?wc-ajax=pi_enq_generate_captcha') ) . '" alt="CAPTCHA" id="captcha_image">';
73 echo '</div>';
74 echo '<a href="#" id="refresh_captcha" title="'.esc_attr($refresh_title).'"><img src="'.esc_url(plugin_dir_url( __FILE__ ).'img/refresh.svg').'" id="captcha_refresh_icon">.</a>';
75 echo '</div>';
76 echo '<label id="captcha_field-error" class="error" for="captcha_field"></label>';
77 echo '</div>';
78 }
79
80
81
82 public function send_generated_captcha_image() {
83 $this->generate_captcha_image();
84 wp_die();
85 }
86
87 public function refreshCaptcha()
88 {
89 // Generate and return a new CAPTCHA image in base64 format
90 ob_start();
91 $this->generate_captcha_image();
92 $imageData = ob_get_contents();
93 ob_end_clean();
94 echo 'data:image/png;base64,' . base64_encode($imageData);
95 wp_die(); // Prevent further execution
96 }
97
98 private function generateCaptchaCode()
99 {
100 // we removed capital I and small l as they look similar in Arial font
101 $characters = $this->get_characters();
102 $captchaCode = '';
103 for ($i = 0; $i < $this->captchaLength; $i++) {
104 $captchaCode .= $characters[rand(0, strlen($characters) - 1)];
105 }
106
107 return $captchaCode;
108 }
109
110 private function generate_captcha_image() {
111 header('Content-type: image/png');
112
113 $captcha_string = $this->generateCaptchaCode();
114
115 WC()->session->set('captcha_code', $captcha_string);
116
117 if($this->useGD === 'gd') {
118 $this->generateCaptchaImageGD($captcha_string);
119 } elseif($this->useGD === 'imagick') {
120 $this->generateCaptchaImageImagick($captcha_string);
121 }
122 }
123
124 private function generateCaptchaImageGD($captchaCode)
125 {
126 // GD-based image generation
127 $image = imagecreatetruecolor($this->width, $this->height);
128 $bgColor = imagecolorallocate($image, 255, 255, 255); // White background
129 imagefill($image, 0, 0, $bgColor);
130
131 // Add noise (random lines)
132 for ($i = 0; $i < 10; $i++) {
133 $lineColor = imagecolorallocate($image, rand(100, 200), rand(100, 200), rand(100, 200));
134 imageline($image, rand(0, $this->width), rand(0, $this->height), rand(0, $this->width), rand(0, $this->height), $lineColor);
135 }
136
137 // Add the CAPTCHA text
138 $textColor = imagecolorallocate($image, 0, 0, 0); // Black text
139 $fontSize = 30;
140 $x = 10; // Starting x position
141 $character_spacing = 30;
142 for ($i = 0; $i < strlen($captchaCode); $i++) {
143 $angle = rand(-10, 10); // Random angle
144 $y = rand(30, 40); // Random y position
145 imagettftext($image, $fontSize, $angle, $x, $y, $textColor, $this->fontPath, $captchaCode[$i]);
146 $x += $character_spacing; // Increment x position
147 }
148
149 // Output image
150 header('Content-Type: image/png');
151 imagepng($image);
152 imagedestroy($image);
153 }
154
155 private function generateCaptchaImageImagick($captchaCode)
156 {
157 // Imagick-based image generation
158 $image = new Imagick();
159 $image->newImage($this->width, $this->height, new ImagickPixel('white'));
160
161 $this->addNoise($image);
162 $this->addCaptchaText($image, $captchaCode);
163 $image->swirlImage(20);
164
165 header('Content-Type: image/png');
166 $image->setImageFormat('png');
167 echo $image;
168
169 $image->clear();
170 $image->destroy();
171 }
172
173 private function addNoise(Imagick $image)
174 {
175 $draw = new ImagickDraw();
176 for ($i = 0; $i < 10; $i++) {
177 $draw->setStrokeColor(new ImagickPixel(sprintf('rgb(%d,%d,%d)', rand(100, 200), rand(100, 200), rand(100, 200))));
178 $draw->setStrokeWidth(1);
179 $draw->line(rand(0, $this->width), rand(0, $this->height), rand(0, $this->width), rand(0, $this->height));
180 }
181 $image->drawImage($draw);
182 }
183
184 private function addCaptchaText(Imagick $image, $captchaCode)
185 {
186 $draw = new ImagickDraw();
187 $draw->setFillColor(new ImagickPixel('black'));
188 $draw->setFont($this->fontPath);
189 $draw->setFontSize(30);
190
191 $x = 10;
192 $characterSpacing = 30;
193 for ($i = 0; $i < strlen($captchaCode); $i++) {
194 $angle = rand(-10, 10);
195 $y = rand(30, 40);
196 $draw->annotation($x, $y, $captchaCode[$i]);
197 $x += $characterSpacing;
198 }
199
200 $image->drawImage($draw);
201 }
202
203 public function enqueueScripts()
204 {
205
206 $script = "
207 jQuery(document).ready(function ($) {
208 $('body').on('click','#refresh_captcha', function (e) {
209 e.preventDefault();
210 jQuery('#pi_enq_captcha').addClass('loading');
211 $.get('" .home_url('?wc-ajax=pi_enq_refresh_captcha'). "', function (data) {
212 $('#captcha_image').attr('src', data); // Update image src with new data URL
213 jQuery('#pi_enq_captcha').removeClass('loading');
214 jQuery('#captcha_field').val(''); // Clear the input field
215 }).fail(function () {
216 console.error('Error refreshing CAPTCHA');
217 jQuery('#pi_enq_captcha').removeClass('loading');
218 });
219 });
220 });
221 ";
222
223 wp_add_inline_script('jquery', $script);
224
225 // Inline CSS for the loading spinner
226 $color_scheme = '#cccccc';
227 $color_scheme_error = '#ff0000';
228 $css = "
229 :root {
230 --captcha_color: $color_scheme;
231 --captcha_error_color: $color_scheme_error;
232 --captcha_border:5px;
233 }
234
235 #pi_enq_captcha_container{
236 display:block;
237 width:100%;
238 margin-bottom:20px;
239 margin-top:20px;
240 }
241
242 #pi_enq_captcha{
243 display:grid;
244 grid-template-columns: 1fr 200px 50px;
245 border:var(--captcha_border, 5px) solid var(--captcha_color, #ccc);
246 border-radius:6px;
247 max-width:600px;
248 }
249
250 @media (max-width: 600px) {
251 #pi_enq_captcha{
252 grid-template-columns: 1fr;
253 }
254
255 #captcha_field{
256 border-bottom:1px solid var(--captcha_color, #ccc) !important;
257 }
258 }
259
260 body:has([data-error-id='captcha-error']) #pi_enq_captcha{
261 border:var(--captcha_border, 5px) solid var(--captcha_error_color, #ff0000);
262 }
263
264 #pi_enq_captcha.loading{
265 opacity:0.5;
266 }
267
268 .captcha_image_container{
269 padding:3px;
270 text-align:center;
271 border-left:1px solid var(--captcha_color, #ccc);
272 background-color:#ffffff;
273 display:flex;
274 align-items:center;
275 }
276
277 #captcha_image{
278 margin:auto;
279 }
280
281 #captcha_refresh_icon{
282 width:30px;
283 }
284
285 #refresh_captcha{
286 cursor:pointer;
287 display:flex;
288 align-items:center;
289 justify-content:center;
290 background:var(--captcha_color, #ccc);
291 font-size:0px;
292 border-left:1px solid var(--captcha_color, #ccc);
293 }
294
295 body:has([data-error-id='captcha-error']) #refresh_captcha{
296 background:var(--captcha_error_color, #ff0000);
297 }
298
299
300 #captcha_field, #captcha_field:focus-visible, #captcha_field:focus{
301 outline: none;
302 border:none;
303 padding:10px;
304 }
305
306 #pi_enq_captcha_container{
307 grid-column:1/3;
308 }
309
310 #captcha_field-error:empty{
311 display:none;
312 }
313 ";
314 // Add custom CSS to the checkout page use dummy dependency
315 wp_register_style('pi-enq-captch-custom-inline-css', false);
316 wp_enqueue_style('pi-enq-captch-custom-inline-css');
317 wp_add_inline_style('pi-enq-captch-custom-inline-css', $css);
318 }
319
320 function get_captcha_placeholder() {
321 $placeholder = get_option('pi_eqw_captcha_placeholder', 'Enter the CAPTCHA');
322 return $placeholder;
323 }
324
325 function get_refresh_captcha_title() {
326 return __('Refresh the CAPTCHA','pisol-enquiry-quotation-woocommerce');
327 }
328
329 function get_captcha_length() {
330 $length = get_option('pi_eqw_captcha_length', 6);
331 $length = absint( apply_filters('pi_enq_captcha_length', $length));
332 return $length > 6 || $length < 1 ? 6 : $length;
333 }
334
335 function captcha_width() {
336 $character_length = $this->get_captcha_length();
337 $width = $character_length * 40;
338 return $width;
339 }
340
341 function get_characters() {
342 $type_of_string = get_option('pi_eqw_captcha_characters', 'mix');
343 if($type_of_string === 'mix') {
344 $characters = 'ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789';
345 }
346
347 if($type_of_string === 'numbers') {
348 $characters = '0123456789';
349 }
350
351 if($type_of_string === 'capital_letter') {
352 $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
353 }
354
355 if($type_of_string === 'small_letter') {
356 $characters = 'abcdefghijklmnopqrstuvwxyz';
357 }
358
359
360 return apply_filters('pi_enq_captcha_characters', $characters);
361 }
362
363 static function captcha_enabled()
364 {
365 $type = get_option('pi_eqw_captcha', '');
366
367 if ($type == 'captcha') {
368 return true;
369 }
370
371 return false;
372 }
373
374 static function image_library_available()
375 {
376 $instance = self::get_instance();
377 return $instance->useGD !== false;
378 }
379
380 static function validateCaptcha($userInput)
381 {
382 if(isset(WC()->session)){
383 $code = WC()->session->get( 'captcha_code');
384
385 if($userInput === $code){
386 return true;
387 }
388 }else{
389 error_log('WC session not found while validating captcha');
390 }
391
392 return false;
393 }
394 }
395
396 // Instantiate the CAPTCHA class
397 PISOL_ENQ_CaptchaGenerator::get_instance();
398