Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * Numeral Captcha
4
 *
5
 * PHP version 5
6
 *
7
 * @category  Text
8
 * @package   Text_CAPTCHA_Numeral
9
 * @author    David Coallier <davidc@agoraproduction.com>
10
 * @author    Marcelo Araujo <msaraujo@php.net>
11
 * @copyright 2002-2007 Agora Production (http://agoraproduction.com)
12
 * @license   http://www.opensource.org/licenses/bsd-license.php BSD
13
 * @link      http://pear.php.net/package/Text_CAPTCHA_Numeral
14
 */
15
require_once 'Text/CAPTCHA/Numeral/NumeralInterface.php';
16
 
17
// {{{ Class Text_CAPTCHA_Numeral
18
/**
19
 * Class used for numeral captchas
20
 *
21
 * This class is intended to be used to generate
22
 * numeral captchas as such as:
23
 * Example:
24
 *  Give me the answer to "54 + 2" to prove that you are human.
25
 *
26
 * @category  Text
27
 * @package   Text_CAPTCHA_Numeral
28
 * @author    David Coallier <davidc@agoraproduction.com>
29
 * @author    Marcelo Araujo <msaraujo@php.net>
30
 * @copyright 2002-2007 Agora Production (http://agoraproduction.com)
31
 * @license   http://www.opensource.org/licenses/bsd-license.php BSD
32
 * @link      http://pear.php.net/package/Text_CAPTCHA_Numeral
33
 */
34
class Text_CAPTCHA_Numeral implements Text_CAPTCHA_Numeral_Interface
35
{
36
    // {{{ Variables
37
    /**
38
     * Minimum range value
39
     *
40
     * This variable holds the minimum range value
41
     * default set to "1"
42
     *
43
     * @access private
44
     * @var    integer $minValue The minimum range value
45
     */
46
    private $minValue = '1';
47
 
48
    /**
49
     * Maximum range value
50
     *
51
     * This variable holds the maximum range value
52
     * default set to "50"
53
     *
54
     * @access private
55
     * @var    integer $maxValue The maximum value of the number range
56
     */
57
    private $maxValue = '50';
58
 
59
    /**
60
     * Operators
61
     *
62
     * The valid operators to use
63
     * in the numeral captcha. We could
64
     * use / and * but not yet.
65
     *
66
     * @access private
67
     * @var    array $operators The operations for the captcha
68
     */
69
    private $operators = array('+','-');
70
 
71
    /**
72
     * Operator to use
73
     *
74
     * This variable is basically the operation
75
     * that we're going to be using in the
76
     * numeral captcha we are about to generate.
77
     *
78
     * @access private
79
     * @var    string $operator The operation's operator
80
     */
81
    private  $operator = '';
82
 
83
    /**
84
     * Mathematical Operation
85
     *
86
     * This is the mathematical operation
87
     * that we are displaying to the user.
88
     *
89
     * @access private
90
     * @var    string $operation The math operation
91
     */
92
    private $operation = '';
93
 
94
    /**
95
     * First number of the operation
96
     *
97
     * This variable holds the first number
98
     * of the numeral operation we are about
99
     * to generate.
100
     *
101
     * @access private
102
     * @var    integer $firstNumber The first number of the operation
103
     */
104
    private $firstNumber = '';
105
 
106
    /**
107
     * Second Number of the operation
108
     *
109
     * This variable holds the value of the
110
     * second variable of the operation we are
111
     * about to generate for the captcha.
112
     *
113
     * @access private
114
     * @var    integer $secondNumber The second number of the operation
115
     */
116
    private $secondNumber = '';
117
 
118
    /**
119
     * The operation answer
120
     *
121
     * The answer to the numeral operation
122
     * we are about to do.
123
     *
124
     * @access private
125
     * @var    integer $answer The mathematical operation answer value.
126
     */
127
    private $answer;
128
 
129
    /**
130
     * A constant that indicates the complexity of mathematical operations
131
     *
132
     * @access public
133
     *
134
     */
135
    const COMPLEXITY_ELEMENTARY = 1;
136
 
137
    /**
138
     * A constant that indicates the complexity of mathematical operations
139
     *
140
     * @access public
141
     *
142
     */
143
    const COMPLEXITY_HIGH_SCHOOL = 2;
144
 
145
    /**
146
     * A constant that indicates the complexity of mathematical operations
147
     *
148
     * @access public
149
     *
150
     */
151
    const COMPLEXITY_UNIVERSITY = 4;
152
 
153
    /**
154
     * Kept for backwards compatibility only; use the short constant.
155
     *
156
     * @deprecated
157
     */
158
    const TEXT_CAPTCHA_NUMERAL_COMPLEXITY_ELEMENTARY = 1;
159
 
160
    /**
161
     * Kept for backwards compatibility only; use the short constant.
162
     *
163
     * @deprecated
164
     */
165
    const TEXT_CAPTCHA_NUMERAL_COMPLEXITY_HIGH_SCHOOL = 2;
166
 
167
    /**
168
     * Kept for backwards compatibility only; use the short constant.
169
     *
170
     * @deprecated
171
     */
172
    const TEXT_CAPTCHA_NUMERAL_COMPLEXITY_UNIVERSITY = 4;
173
 
174
 
175
 
176
    // }}}
177
    // {{{ Constructor
178
    /**
179
     * Constructor with different levels of mathematical operations sets
180
     *
181
     * @param constant $complexityType How complex the captcha equation shall be.
182
     *                                 See the COMPLEXITY constants.
183
     * @param integer  $minValue       Minimal value of a number
184
     * @param integer  $maxValue       Maximal value of a number
185
     */
186
    public function __construct(
187
        $complexityType = self::COMPLEXITY_ELEMENTARY,
188
        $minValue = 1, $maxValue = 50
189
    ) {
190
 
191
        $this->minValue = (int)$minValue;
192
        $this->maxValue = (int)$maxValue;
193
 
194
        switch ($complexityType) {
195
        case self::COMPLEXITY_HIGH_SCHOOL:
196
            $this->operators[] = '*';
197
            if ($this->maxValue < 70) {
198
                $this->maxValue = '70';
199
            }
200
 
201
            break;
202
        case self::COMPLEXITY_UNIVERSITY:
203
            $this->operators[] = '*';
204
            $this->operators[] = '%';
205
            $this->operators[] = '/';
206
            $this->operators[] = '^';
207
            $this->operators[] = '!';
208
            if ($this->maxValue < 100) {
209
                $this->maxValue = '100';
210
            }
211
 
212
            break;
213
        case self::COMPLEXITY_ELEMENTARY:
214
        default:
215
            break;
216
        }
217
 
218
        $this->generateFirstNumber();
219
        $this->generateSecondNumber();
220
        $this->generateOperator();
221
        $this->generateOperation();
222
    }
223
    // }}}
224
    // {{{ private function setRangeMinimum
225
    /**
226
     * Set Range Minimum value
227
     *
228
     * This function give the developer the ability
229
     * to set the range minimum value so the operations
230
     * can be bigger, smaller, etc.
231
     *
232
     * @param integer $minValue The minimum value
233
     *
234
     * @return void
235
     */
236
    private function setRangeMinimum($minValue = '1')
237
    {
238
        $this->minValue = (int)$minValue;
239
    }
240
    // }}}
241
    // {{{ private function generateFirstNumber
242
    /**
243
     * Sets the first number
244
     *
245
     * This function sets the first number
246
     * of the operation by calling the generateNumber
247
     * function that generates a random number.
248
     *
249
     * @return void
250
     *
251
     * @see $this->firstNumber, $this->generateNumber
252
     */
253
    private function generateFirstNumber()
254
    {
255
        $this->setFirstNumber($this->generateNumber());
256
    }
257
    // }}}
258
    // {{{ private function generateSecondNumber
259
    /**
260
     * Sets second number
261
     *
262
     * This function sets the second number of the
263
     * operation by calling generateNumber()
264
     *
265
     * @return void
266
     *
267
     * @see $this->secondNumber, $this->generateNumber()
268
     */
269
    private function generateSecondNumber()
270
    {
271
        $this->setSecondNumber($this->generateNumber());
272
    }
273
    // }}}
274
    // {{{ private function generateOperator
275
    /**
276
     * Sets the operation operator
277
     *
278
     * This function sets the operation operator by
279
     * getting the array value of an array_rand() of
280
     * the $this->operators() array.
281
     *
282
     * @return void
283
     *
284
     * @see $this->operators, $this->operator
285
     */
286
    private function generateOperator()
287
    {
288
        $this->operator = $this->operators[array_rand($this->operators)];
289
    }
290
    // }}}
291
    // {{{ private function setAnswer
292
    /**
293
     * Sets the answer value
294
     *
295
     * This function will accept the parameters which is
296
     * basically the result of the function we have done
297
     * and it will set $this->answer with it.
298
     *
299
     * @param integer $answerValue The answer value
300
     *
301
     * @return void
302
     *
303
     * @see $this->answer
304
     */
305
    private function setAnswer($answerValue)
306
    {
307
        $this->answer = $answerValue;
308
        return $this;
309
    }
310
    // }}}
311
    // {{{ private function setFirstNumber
312
    /**
313
     * Set First number
314
     *
315
     * This function sets the first number
316
     * to the value passed to the function
317
     *
318
     * @param integer $value The first number value.
319
     *
320
     * @return Text_CAPTCHA_Numeral The self object
321
     */
322
    private function setFirstNumber($value)
323
    {
324
        $this->firstNumber = (int)$value;
325
        return $this;
326
    }
327
    // }}}
328
    // {{{ private function setSecondNumber
329
    /**
330
     * Sets the second number
331
     *
332
     * This function sets the second number
333
     * with the value passed to it.
334
     *
335
     * @param integer $value The second number new value.
336
     *
337
     * @return Text_CAPTCHA_Numeral The self object
338
     */
339
    private function setSecondNumber($value)
340
    {
341
        $this->secondNumber = (int)$value;
342
        return $this;
343
    }
344
    // }}}
345
    // {{{ private function setOperation
346
    /**
347
     * Set "operation" string the user needs to solve.
348
     *
349
     * This variable sets the operation variable
350
     * by taking the firstNumber, secondNumber and operator
351
     *
352
     * @param string $type May be null, or "F" to indicate a factorial operation
353
     *
354
     * @return void
355
     *
356
     * @see $this->operation
357
     */
358
    private function setOperation($type = null)
359
    {
360
        if ($type == 'F') {
361
            $this->operation = $this->getFirstNumber() . ' ' . $this->operator;
362
        } else {
363
            $this->operation = $this->getFirstNumber() . ' ' .
364
            $this->operator . ' ' .
365
            $this->getSecondNumber();
366
        }
367
        return $this;
368
    }
369
    // }}}
370
    // {{{ private function generateNumber
371
    /**
372
     * Generate a number
373
     *
374
     * This function takes the parameters that are in
375
     * the $this->maxValue and $this->minValue and get
376
     * the random number from them using mt_rand()
377
     *
378
     * @return integer Random value between minValue and maxValue
379
     */
380
    private function generateNumber()
381
    {
382
        return mt_rand($this->minValue, $this->maxValue);
383
    }
384
    // }}}
385
    // {{{ private function doAdd
386
    /**
387
     * Adds values
388
     *
389
     * This function will add the firstNumber and the
390
     * secondNumber value and then call setAnswer to
391
     * set the answer value.
392
     *
393
     * @return void
394
     *
395
     * @see $this->firstNumber, $this->secondNumber, $this->setAnswer()
396
     */
397
    private function doAdd()
398
    {
399
        $answer = $this->getFirstNumber() + $this->getSecondNumber();
400
        $this->setAnswer($answer);
401
    }
402
    // }}}
403
    // {{{ private function doMultiplication
404
    /**
405
     * Do Multiplication
406
     *
407
     * This method will multiply two numbers
408
     *
409
     * @return void
410
     *
411
     * @see $this->firstNumber, $this->secondNumber, $this->setAnswer
412
     */
413
    private function doMultiplication()
414
    {
415
        $this->setAnswer($this->getFirstNumber() * $this->getSecondNumber());
416
    }
417
    // }}}
418
    // {{{ private function doDivision
419
    /**
420
     * Do Division
421
     *
422
     * This function executes a division based on the two
423
     * numbers.
424
     *
425
     * @param integer $firstNumber  The first number of the operation.
426
     *                              This is by default set to null.
427
     * @param integer $secondNumber The second number of the operation
428
     *                              This is by default set to null.
429
     *
430
     * @return void
431
     */
432
    private function doDivision($firstNumber = null, $secondNumber = null)
433
    {
434
        if (is_null($firstNumber)) {
435
            $firstNumber = $this->getFirstNumber();
436
        }
437
 
438
        if (is_null($secondNumber)) {
439
            $secondNumber = $this->getSecondNumber();
440
        }
441
 
442
        if ($secondNumber == 0) {
443
            ++$secondNumber;
444
            $this->doDivision($firstNumber, $secondNumber);
445
            return;
446
        }
447
 
448
        if ($firstNumber == 0) {
449
            $this->doDivision(++$firstNumber, $secondNumber);
450
            return;
451
        }
452
 
453
        if ($firstNumber % $secondNumber != 0) {
454
            --$firstNumber;
455
            --$secondNumber;
456
 
457
            $this->doDivision($firstNumber, $secondNumber);
458
            return;
459
        }
460
 
461
        $this->setFirstNumber($firstNumber)
462
            ->setSecondNumber($secondNumber)
463
            ->setOperation()
464
            ->setAnswer($this->getFirstNumber() / $this->getSecondNumber());
465
    }
466
    // }}}
467
    // {{{ private function doModulus
468
    /**
469
     * Do modulus
470
     *
471
     * This method will do a modulus operation between two numbers
472
     *
473
     * @return void
474
     *
475
     * @see $this->firstNumber, $this->secondNumber, $this->setAnswer()
476
     */
477
    private function doModulus()
478
    {
479
        $first  = $this->getFirstNumber();
480
        $second = $this->getSecondNumber();
481
 
482
        if ($first == $second) {
483
            $this->generateSecondNumber();
484
            $this->doModulus();
485
            return;
486
        }
487
 
488
        $this->setAnswer($this->getFirstNumber() % $this->getSecondNumber());
489
    }
490
    // }}}
491
    // {{{ private function doSubstract
492
    /**
493
     * Does a substract on the values
494
     *
495
     * This function executes a substraction on the firstNumber
496
     * and the secondNumber to then call $this->setAnswer to set
497
     * the answer value.
498
     *
499
     * If the firstnumber value is smaller than the secondnumber value
500
     * then we regenerate the first number and regenerate the operation.
501
     *
502
     * @return void
503
     *
504
     * @see $this->firstNumber, $this->secondNumber, $this->setAnswer()
505
     */
506
    private function doSubstract()
507
    {
508
         $first  = $this->getFirstNumber();
509
         $second = $this->getSecondNumber();
510
 
511
        /**
512
         * Check if firstNumber is smaller than secondNumber
513
         */
514
        if ($first < $second) {
515
            $this->setFirstNumber($second)
516
                ->setSecondNumber($first)
517
                ->setOperation();
518
        }
519
 
520
        $answer = $this->getFirstNumber() - $this->getSecondNumber();
521
        $this->setAnswer($answer);
522
    }
523
    // }}}
524
    // {{{ private function doExponentiation
525
    /**
526
     * Does an exponentiation on the values
527
     *
528
     * This function executes an exponentiation
529
     *
530
     * @return void
531
     *
532
     * @see $this->setOperation, $this->getFirstNumber
533
     *      $this->getSecondNumber, $this->setAnswer()
534
     */
535
    private function doExponentiation()
536
    {
537
        $this->setOperation()
538
            ->setAnswer(pow($this->getFirstNumber(), $this->getSecondNumber()));
539
    }
540
    // }}}
541
    // {{{ private function doFactorial
542
    /**
543
     * Call static factorial method
544
     *
545
     * @return void
546
     */
547
    private function doFactorial()
548
    {
549
        $this->setOperation('F')
550
            ->setAnswer($this->calculateFactorial($this->getFirstNumber()));
551
    }
552
    // }}}
553
    // {{{ private function calculateFactorial
554
    /**
555
     * Calculate factorial given an integer number
556
     *
557
     * @param integer $n The factorial to calculate
558
     *
559
     * @return integer The calculated value
560
     */
561
    private function calculateFactorial($n)
562
    {
563
        return $n <= 1 ? 1 : $n * $this->calculateFactorial($n - 1);
564
    }
565
    // }}}
566
    // {{{ private function generateOperation
567
    /**
568
     * Generate the operation
569
     *
570
     * This function will call the setOperation() function
571
     * to set the operation string that will be called
572
     * to display the operation, and call the function necessary
573
     * depending on which operation is set by this->operator.
574
     *
575
     * @return void
576
     *
577
     * @see $this->setOperation(), $this->operator
578
     */
579
    private function generateOperation()
580
    {
581
        $this->setOperation();
582
 
583
        switch ($this->operator) {
584
        case '+':
585
            $this->doAdd();
586
            break;
587
        case '-':
588
            $this->doSubstract();
589
            break;
590
        case '*':
591
            $this->doMultiplication();
592
            break;
593
        case '%':
594
            $this->doModulus();
595
            break;
596
        case '/':
597
            $this->doDivision();
598
            break;
599
        case '^':
600
            $this->minValue = 10;
601
            $this->doExponentiation();
602
            break;
603
        case '!':
604
            $this->minValue = 1;
605
            $this->maxValue = 10;
606
            $this->generateFirstNumber();
607
            $this->doFactorial();
608
            break;
609
        default:
610
            $this->doAdd();
611
            break;
612
        }
613
    }
614
    // }}}
615
    // {{{ public function getOperation
616
    /**
617
     * Get operation
618
     *
619
     * This function will get the operation
620
     * string from $this->operation
621
     *
622
     * @return string The operation String
623
     */
624
    public function getOperation()
625
    {
626
        return $this->operation;
627
    }
628
    // }}}
629
    // {{{ public function getAnswer
630
    /**
631
     * Get the answer value
632
     *
633
     * This function will retrieve the answer
634
     * value from this->answer and return it so
635
     * we can then display it to the user.
636
     *
637
     * @return string The operation answer value.
638
     */
639
    public function getAnswer()
640
    {
641
        return $this->answer;
642
    }
643
    // }}}
644
    // {{{ public function getFirstNumber
645
    /**
646
     * Get the first number
647
     *
648
     * This function will get the first number
649
     * value from $this->firstNumber
650
     *
651
     * @return integer $this->firstNumber The firstNumber
652
     */
653
    public function getFirstNumber()
654
    {
655
        return $this->firstNumber;
656
    }
657
    // }}}
658
    // {{{ public function getSecondNumber
659
    /**
660
     * Get the second number value
661
     *
662
     * This function will return the second number value
663
     *
664
     * @return integer $this->secondNumber The second number
665
     */
666
    public function getSecondNumber()
667
    {
668
        return $this->secondNumber;
669
    }
670
    // }}}
671
}
672
// }}}