Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * Require Image_Text class for generating the text.
4
 */
5
require_once 'Text/CAPTCHA.php';
6
require_once 'Image/Text.php';
7
 
8
/**
9
 * Text_CAPTCHA_Driver_Image - Text_CAPTCHA driver graphical CAPTCHAs
10
 *
11
 * Class to create a graphical Turing test
12
 *
13
 * @author  Christian Wenz <wenz@php.net>
14
 * @license BSD License
15
 * @todo refine the obfuscation algorithm :-)
16
 * @todo consider removing Image_Text dependency
17
 */
18
 
19
class Text_CAPTCHA_Driver_Image extends Text_CAPTCHA
20
{
21
 
22
    /**
23
     * Image object
24
     *
25
     * @access private
26
     * @var resource
27
     */
28
    var $_im;
29
 
30
    /**
31
     * Image_Text object
32
     *
33
     * @access private
34
     * @var resource
35
     */
36
    var $_imt;
37
 
38
    /**
39
     * Width of CAPTCHA
40
     *
41
     * @access private
42
     * @var int
43
     */
44
    var $_width;
45
 
46
    /**
47
     * Height of CAPTCHA
48
     *
49
     * @access private
50
     * @var int
51
     */
52
    var $_height;
53
 
54
    /**
55
     * CAPTCHA output format
56
     *
57
     * @access private
58
     * @var string
59
     */
60
    var $_output;
61
 
62
    /**
63
     * Further options (here: for Image_Text)
64
     *
65
     * @access private
66
     * @var array
67
     */
68
    var $_imageOptions = array(
69
        'font_size'        => 24,
70
        'font_path'        => './',
71
        'font_file'        => 'COUR.TTF',
72
        'text_color'       => '#000000',
73
        'lines_color'      => '#CACACA',
74
        'background_color' => '#555555',
75
        'antialias'        => false);
76
 
77
    /**
78
     * Whether the immage resource has been created
79
     *
80
     * @access private
81
     * @var boolean
82
     */
83
    var $_created = false;
84
 
85
    /**
86
     * Last error
87
     *
88
     * @access protected
89
     * @var PEAR_Error
90
     */
91
    var $_error = null;
92
 
93
    /**
94
     * init function
95
     *
96
     * Initializes the new Text_CAPTCHA_Driver_Image object and creates a GD image
97
     *
98
     * @param array $options CAPTCHA options
99
     *
100
     * @access public
101
     * @return mixed true upon success, PEAR error otherwise
102
     */
103
    function init($options = array())
104
    {
105
        if (!is_array($options)) {
106
            // Compatibility mode ... in future versions, these two
107
            // lines of code will be used:
108
            // $this->_error = PEAR::raiseError('You need to provide a set of CAPTCHA options!');
109
            // return $this->_error;
110
            $o = array();
111
            $args = func_get_args();
112
            if (isset($args[0])) {
113
                $o['width'] = $args[0];
114
            }
115
            if (isset($args[1])) {
116
                $o['height'] = $args[1];
117
            }
118
            if (isset($args[2]) && $args[2] != null) {
119
                $o['phrase'] = $args[2];
120
            }
121
            if (isset($args[3]) && is_array($args[3])) {
122
                $o['imageOptions'] = $args[3];
123
            }
124
            $options = $o;
125
        }
126
        if (is_array($options)) {
127
            if (isset($options['width']) && is_int($options['width'])) {
128
                $this->_width = $options['width'];
129
            } else {
130
                $this->_width = 200;
131
            }
132
            if (isset($options['height']) && is_int($options['height'])) {
133
                $this->_height = $options['height'];
134
            } else {
135
                $this->_height = 80;
136
            }
137
            if (!isset($options['phrase']) || empty($options['phrase'])) {
138
                $phraseoptions = (isset($options['phraseOptions']) && is_array($options['phraseOptions'])) ? $options['phraseOptions'] : array();
139
                $this->_createPhrase($phraseoptions);
140
            } else {
141
                $this->_phrase = $options['phrase'];
142
            }
143
            if (!isset($options['output']) || empty($options['output'])) {
144
                $this->_output = 'resource';
145
            } else {
146
                $this->_output = $options['output'];
147
            }
148
            if (isset($options['imageOptions']) && is_array($options['imageOptions']) && count($options['imageOptions']) > 0) {
149
                $this->_imageOptions = array_merge($this->_imageOptions, $options['imageOptions']);
150
            }
151
            return true;
152
        }
153
    }
154
 
155
    /**
156
     * Create random CAPTCHA phrase, Image edition (with size check)
157
     *
158
     * This method creates a random phrase, maximum 8 characters or width / 25, whatever is smaller
159
     *
160
     * @param array $options Optionally supply advanced options for the phrase creation
161
     *
162
     * @access private
163
     * @return void
164
     */
165
    function _createPhrase($options = array())
166
    {
167
        $len = intval(min(8, $this->_width / 25));
168
        if (!is_array($options) || count($options) === 0) {
169
            $this->_phrase = Text_Password::create($len);
170
        } else {
171
            if (count($options) === 1) {
172
                $this->_phrase = Text_Password::create($len, $options[0]);
173
            } else {
174
                $this->_phrase = Text_Password::create($len, $options[0], $options[1]);
175
            }
176
        }
177
        $this->_created = false;
178
    }
179
 
180
    /**
181
     * Create CAPTCHA image
182
     *
183
     * This method creates a CAPTCHA image
184
     *
185
     * @access  private
186
     * @return  void   PEAR_Error on error
187
     */
188
    function _createCAPTCHA()
189
    {
190
        if ($this->_error) {
191
            return $this->_error;
192
        }
193
        if ($this->_created) {
194
            return;
195
        }
196
        $options['canvas'] = array(
197
            'width' => $this->_width,
198
            'height' => $this->_height
199
        );
200
        $options['width'] = $this->_width - 20;
201
        $options['height'] = $this->_height - 20;
202
        $options['cx'] = ceil(($this->_width) / 2 + 10);
203
        $options['cy'] = ceil(($this->_height) / 2 + 10);
204
        $options['angle'] = rand(0, 30) - 15;
205
        $options['font_size'] = $this->_imageOptions['font_size'];
206
        $options['font_path'] = $this->_imageOptions['font_path'];
207
        $options['font_file'] = $this->_imageOptions['font_file'];
208
        $options['color'] = array($this->_imageOptions['text_color']);
209
        $options['background_color'] = $this->_imageOptions['background_color'];
210
        $options['max_lines'] = 1;
211
        $options['mode'] = 'auto';
212
        do {
213
            $this->_imt = new Image_Text(
214
                $this->_phrase,
215
                $options
216
            );
217
            if (PEAR::isError($e = $this->_imt->init())) {
218
                $this->_error = PEAR::raiseError(
219
                    sprintf('Error initializing Image_Text (%s)', $e->getMessage()));
220
                return $this->_error;
221
            } else {
222
                $this->_created = true;
223
            }
224
            $result = $this->_imt->measurize();
225
        } while ($result === false && --$options['font_size'] > 0);
226
        if ($result === false) {
227
            $this->_error = PEAR::raiseError('The text provided does not fit in the image dimensions');
228
            return $this->_error;
229
        }
230
        $this->_imt->render();
231
        $this->_im =& $this->_imt->getImg();
232
 
233
        if (isset($this->_imageOptions['antialias']) && $this->_imageOptions['antialias'] === true && function_exists('imageantialias')) {
234
            imageantialias($this->_im, true);
235
        }
236
 
237
        $colors = $this->_imt->_convertString2RGB($this->_imageOptions['lines_color']);
238
        $lines_color = imagecolorallocate($this->_im, $colors['r'], $colors['g'], $colors['b']);
239
        //some obfuscation
240
        for ($i = 0; $i < 3; $i++) {
241
            $x1 = rand(0, $this->_width - 1);
242
            $y1 = rand(0, round($this->_height / 10, 0));
243
            $x2 = rand(0, round($this->_width / 10, 0));
244
            $y2 = rand(0, $this->_height - 1);
245
            imageline($this->_im, $x1, $y1, $x2, $y2, $lines_color);
246
            $x1 = rand(0, $this->_width - 1);
247
            $y1 = $this->_height - rand(1, round($this->_height / 10, 0));
248
            $x2 = $this->_width - rand(1, round($this->_width / 10, 0));
249
            $y2 = rand(0, $this->_height - 1);
250
            imageline($this->_im, $x1, $y1, $x2, $y2, $lines_color);
251
            $cx = rand(0, $this->_width - 50) + 25;
252
            $cy = rand(0, $this->_height - 50) + 25;
253
            $w = rand(1, 24);
254
            imagearc($this->_im, $cx, $cy, $w, $w, 0, 360, $lines_color);
255
        }
256
    }
257
 
258
    /**
259
     * Return CAPTCHA as image resource
260
     *
261
     * This method returns the CAPTCHA depending on the output format
262
     *
263
     * @access  public
264
     * @return  mixed        image resource or PEAR error
265
     */
266
    function getCAPTCHA()
267
    {
268
        $retval = $this->_createCAPTCHA();
269
        if (PEAR::isError($retval)) {
270
            return PEAR::raiseError($retval->getMessage());
271
        }
272
 
273
        if ($this->_output == 'gif' && !function_exists('imagegif')) {
274
            $this->_output = 'png';
275
        }
276
 
277
        switch ($this->_output) {
278
            case 'png':
279
                return $this->getCAPTCHAAsPNG();
280
                break;
281
            case 'jpg':
282
            case 'jpeg':
283
                return $this->getCAPTCHAAsJPEG();
284
                break;
285
            case 'gif':
286
                return $this->getCAPTCHAAsGIF();
287
                break;
288
            case 'resource':
289
            default:
290
                return $this->_im;
291
        }
292
    }
293
 
294
    /**
295
     * Return CAPTCHA as PNG
296
     *
297
     * This method returns the CAPTCHA as PNG
298
     *
299
     * @access  public
300
     * @return  mixed        image contents or PEAR error
301
     */
302
    function getCAPTCHAAsPNG()
303
    {
304
        $retval = $this->_createCAPTCHA();
305
        if (PEAR::isError($retval)) {
306
            return PEAR::raiseError($retval->getMessage());
307
        }
308
 
309
        if (is_resource($this->_im)) {
310
            ob_start();
311
            imagepng($this->_im);
312
            $data = ob_get_contents();
313
            ob_end_clean();
314
            return $data;
315
        } else {
316
            $this->_error = PEAR::raiseError('Error creating CAPTCHA image (font missing?!)');
317
            return $this->_error;
318
        }
319
    }
320
 
321
    /**
322
     * Return CAPTCHA as JPEG
323
     *
324
     * This method returns the CAPTCHA as JPEG
325
     *
326
     * @access  public
327
     * @return  mixed        image contents or PEAR error
328
     */
329
    function getCAPTCHAAsJPEG()
330
    {
331
        $retval = $this->_createCAPTCHA();
332
        if (PEAR::isError($retval)) {
333
            return PEAR::raiseError($retval->getMessage());
334
        }
335
 
336
        if (is_resource($this->_im)) {
337
            ob_start();
338
            imagejpeg($this->_im);
339
            $data = ob_get_contents();
340
            ob_end_clean();
341
            return $data;
342
        } else {
343
            $this->_error = PEAR::raiseError('Error creating CAPTCHA image (font missing?!)');
344
            return $this->_error;
345
        }
346
    }
347
 
348
    /**
349
     * Return CAPTCHA as GIF
350
     *
351
     * This method returns the CAPTCHA as GIF
352
     *
353
     * @access  public
354
     * @return  mixed        image contents or PEAR error
355
     */
356
    function getCAPTCHAAsGIF()
357
    {
358
        $retval = $this->_createCAPTCHA();
359
        if (PEAR::isError($retval)) {
360
            return PEAR::raiseError($retval->getMessage());
361
        }
362
 
363
        if (is_resource($this->_im)) {
364
            ob_start();
365
            imagegif($this->_im);
366
            $data = ob_get_contents();
367
            ob_end_clean();
368
            return $data;
369
        } else {
370
            $this->_error = PEAR::raiseError('Error creating CAPTCHA image (font missing?!)');
371
            return $this->_error;
372
        }
373
    }
374
 
375
    /**
376
     * __wakeup method (PHP 5 only)
377
     *
378
     * @return void
379
     */
380
    function __wakeup()
381
    {
382
        $this->_created = false;
383
    }
384
}