Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Faker\Provider;
4
 
5
use Faker\DefaultGenerator;
6
use Faker\Generator;
7
use Faker\UniqueGenerator;
8
use Faker\ValidGenerator;
9
 
10
class Base
11
{
12
    /**
13
     * @var \Faker\Generator
14
     */
15
    protected $generator;
16
 
17
    /**
18
     * @var \Faker\UniqueGenerator
19
     */
20
    protected $unique;
21
 
22
    public function __construct(Generator $generator)
23
    {
24
        $this->generator = $generator;
25
    }
26
 
27
    /**
28
     * Returns a random number between 0 and 9
29
     *
30
     * @return int
31
     */
32
    public static function randomDigit()
33
    {
34
        return mt_rand(0, 9);
35
    }
36
 
37
    /**
38
     * Returns a random number between 1 and 9
39
     *
40
     * @return int
41
     */
42
    public static function randomDigitNotNull()
43
    {
44
        return mt_rand(1, 9);
45
    }
46
 
47
    /**
48
     * Generates a random digit, which cannot be $except
49
     *
50
     * @param int $except
51
     *
52
     * @return int
53
     */
54
    public static function randomDigitNot($except)
55
    {
56
        $result = self::numberBetween(0, 8);
57
 
58
        if ($result >= $except) {
59
            ++$result;
60
        }
61
 
62
        return $result;
63
    }
64
 
65
    /**
66
     * Returns a random integer with 0 to $nbDigits digits.
67
     *
68
     * The maximum value returned is mt_getrandmax()
69
     *
70
     * @param int  $nbDigits Defaults to a random number between 1 and 9
71
     * @param bool $strict   Whether the returned number should have exactly $nbDigits
72
     *
73
     * @example 79907610
74
     *
75
     * @return int
76
     */
77
    public static function randomNumber($nbDigits = null, $strict = false)
78
    {
79
        if (!is_bool($strict)) {
80
            throw new \InvalidArgumentException('randomNumber() generates numbers of fixed width. To generate numbers between two boundaries, use numberBetween() instead.');
81
        }
82
 
83
        if (null === $nbDigits) {
84
            $nbDigits = static::randomDigitNotNull();
85
        }
86
        $max = 10 ** $nbDigits - 1;
87
 
88
        if ($max > mt_getrandmax()) {
89
            throw new \InvalidArgumentException('randomNumber() can only generate numbers up to mt_getrandmax()');
90
        }
91
 
92
        if ($strict) {
93
            return mt_rand(10 ** ($nbDigits - 1), $max);
94
        }
95
 
96
        return mt_rand(0, $max);
97
    }
98
 
99
    /**
100
     * Return a random float number
101
     *
102
     * @param int       $nbMaxDecimals
103
     * @param float|int $min
104
     * @param float|int $max
105
     *
106
     * @example 48.8932
107
     *
108
     * @return float
109
     */
110
    public static function randomFloat($nbMaxDecimals = null, $min = 0, $max = null)
111
    {
112
        if (null === $nbMaxDecimals) {
113
            $nbMaxDecimals = static::randomDigit();
114
        }
115
 
116
        if (null === $max) {
117
            $max = static::randomNumber();
118
 
119
            if ($min > $max) {
120
                $max = $min;
121
            }
122
        }
123
 
124
        if ($min > $max) {
125
            $tmp = $min;
126
            $min = $max;
127
            $max = $tmp;
128
        }
129
 
130
        return round($min + mt_rand() / mt_getrandmax() * ($max - $min), $nbMaxDecimals);
131
    }
132
 
133
    /**
134
     * Returns a random number between $int1 and $int2 (any order)
135
     *
136
     * @param int $int1 default to 0
137
     * @param int $int2 defaults to 32 bit max integer, ie 2147483647
138
     *
139
     * @example 79907610
140
     *
141
     * @return int
142
     */
143
    public static function numberBetween($int1 = 0, $int2 = 2147483647)
144
    {
145
        $min = $int1 < $int2 ? $int1 : $int2;
146
        $max = $int1 < $int2 ? $int2 : $int1;
147
 
148
        return mt_rand($min, $max);
149
    }
150
 
151
    /**
152
     * Returns the passed value
153
     */
154
    public static function passthrough($value)
155
    {
156
        return $value;
157
    }
158
 
159
    /**
160
     * Returns a random letter from a to z
161
     *
162
     * @return string
163
     */
164
    public static function randomLetter()
165
    {
166
        return chr(mt_rand(97, 122));
167
    }
168
 
169
    /**
170
     * Returns a random ASCII character (excluding accents and special chars)
171
     *
172
     * @return string
173
     */
174
    public static function randomAscii()
175
    {
176
        return chr(mt_rand(33, 126));
177
    }
178
 
179
    /**
180
     * Returns randomly ordered subsequence of $count elements from a provided array
181
     *
182
     * @param array $array           Array to take elements from. Defaults to a-c
183
     * @param int   $count           Number of elements to take.
184
     * @param bool  $allowDuplicates Allow elements to be picked several times. Defaults to false
185
     *
186
     * @throws \LengthException When requesting more elements than provided
187
     *
188
     * @return array New array with $count elements from $array
189
     */
190
    public static function randomElements($array = ['a', 'b', 'c'], $count = 1, $allowDuplicates = false)
191
    {
192
        $traversables = [];
193
 
194
        if ($array instanceof \Traversable) {
195
            foreach ($array as $element) {
196
                $traversables[] = $element;
197
            }
198
        }
199
 
200
        $arr = count($traversables) ? $traversables : $array;
201
 
202
        $allKeys = array_keys($arr);
203
        $numKeys = count($allKeys);
204
 
205
        if (!$allowDuplicates && $numKeys < $count) {
206
            throw new \LengthException(sprintf('Cannot get %d elements, only %d in array', $count, $numKeys));
207
        }
208
 
209
        $highKey = $numKeys - 1;
210
        $keys = $elements = [];
211
        $numElements = 0;
212
 
213
        while ($numElements < $count) {
214
            $num = mt_rand(0, $highKey);
215
 
216
            if (!$allowDuplicates) {
217
                if (isset($keys[$num])) {
218
                    continue;
219
                }
220
                $keys[$num] = true;
221
            }
222
 
223
            $elements[] = $arr[$allKeys[$num]];
224
            ++$numElements;
225
        }
226
 
227
        return $elements;
228
    }
229
 
230
    /**
231
     * Returns a random element from a passed array
232
     *
233
     * @param array $array
234
     */
235
    public static function randomElement($array = ['a', 'b', 'c'])
236
    {
237
        if (!$array || ($array instanceof \Traversable && !count($array))) {
238
            return null;
239
        }
240
        $elements = static::randomElements($array, 1);
241
 
242
        return $elements[0];
243
    }
244
 
245
    /**
246
     * Returns a random key from a passed associative array
247
     *
248
     * @param array $array
249
     *
250
     * @return int|string|null
251
     */
252
    public static function randomKey($array = [])
253
    {
254
        if (!$array) {
255
            return null;
256
        }
257
        $keys = array_keys($array);
258
 
259
        return $keys[mt_rand(0, count($keys) - 1)];
260
    }
261
 
262
    /**
263
     * Returns a shuffled version of the argument.
264
     *
265
     * This function accepts either an array, or a string.
266
     *
267
     * @example $faker->shuffle([1, 2, 3]); // [2, 1, 3]
268
     * @example $faker->shuffle('hello, world'); // 'rlo,h eold!lw'
269
     *
270
     * @see shuffleArray()
271
     * @see shuffleString()
272
     *
273
     * @param array|string $arg The set to shuffle
274
     *
275
     * @return array|string The shuffled set
276
     */
277
    public static function shuffle($arg = '')
278
    {
279
        if (is_array($arg)) {
280
            return static::shuffleArray($arg);
281
        }
282
 
283
        if (is_string($arg)) {
284
            return static::shuffleString($arg);
285
        }
286
 
287
        throw new \InvalidArgumentException('shuffle() only supports strings or arrays');
288
    }
289
 
290
    /**
291
     * Returns a shuffled version of the array.
292
     *
293
     * This function does not mutate the original array. It uses the
294
     * Fisher–Yates algorithm, which is unbiased, together with a Mersenne
295
     * twister random generator. This function is therefore more random than
296
     * PHP's shuffle() function, and it is seedable.
297
     *
298
     * @see http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
299
     *
300
     * @example $faker->shuffleArray([1, 2, 3]); // [2, 1, 3]
301
     *
302
     * @param array $array The set to shuffle
303
     *
304
     * @return array The shuffled set
305
     */
306
    public static function shuffleArray($array = [])
307
    {
308
        $shuffledArray = [];
309
        $i = 0;
310
        reset($array);
311
 
312
        foreach ($array as $key => $value) {
313
            if ($i == 0) {
314
                $j = 0;
315
            } else {
316
                $j = mt_rand(0, $i);
317
            }
318
 
319
            if ($j == $i) {
320
                $shuffledArray[] = $value;
321
            } else {
322
                $shuffledArray[] = $shuffledArray[$j];
323
                $shuffledArray[$j] = $value;
324
            }
325
            ++$i;
326
        }
327
 
328
        return $shuffledArray;
329
    }
330
 
331
    /**
332
     * Returns a shuffled version of the string.
333
     *
334
     * This function does not mutate the original string. It uses the
335
     * Fisher–Yates algorithm, which is unbiased, together with a Mersenne
336
     * twister random generator. This function is therefore more random than
337
     * PHP's shuffle() function, and it is seedable. Additionally, it is
338
     * UTF8 safe if the mb extension is available.
339
     *
340
     * @see http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
341
     *
342
     * @example $faker->shuffleString('hello, world'); // 'rlo,h eold!lw'
343
     *
344
     * @param string $string   The set to shuffle
345
     * @param string $encoding The string encoding (defaults to UTF-8)
346
     *
347
     * @return string The shuffled set
348
     */
349
    public static function shuffleString($string = '', $encoding = 'UTF-8')
350
    {
351
        if (function_exists('mb_strlen')) {
352
            // UTF8-safe str_split()
353
            $array = [];
354
            $strlen = mb_strlen($string, $encoding);
355
 
356
            for ($i = 0; $i < $strlen; ++$i) {
357
                $array[] = mb_substr($string, $i, 1, $encoding);
358
            }
359
        } else {
360
            $array = str_split($string, 1);
361
        }
362
 
363
        return implode('', static::shuffleArray($array));
364
    }
365
 
366
    private static function replaceWildcard($string, $wildcard, $callback)
367
    {
368
        if (($pos = strpos($string, $wildcard)) === false) {
369
            return $string;
370
        }
371
 
372
        for ($i = $pos, $last = strrpos($string, $wildcard, $pos) + 1; $i < $last; ++$i) {
373
            if ($string[$i] === $wildcard) {
374
                $string[$i] = call_user_func($callback);
375
            }
376
        }
377
 
378
        return $string;
379
    }
380
 
381
    /**
382
     * Replaces all hash sign ('#') occurrences with a random number
383
     * Replaces all percentage sign ('%') occurrences with a not null number
384
     *
385
     * @param string $string String that needs to bet parsed
386
     *
387
     * @return string
388
     */
389
    public static function numerify($string = '###')
390
    {
391
        // instead of using randomDigit() several times, which is slow,
392
        // count the number of hashes and generate once a large number
393
        $toReplace = [];
394
 
395
        if (($pos = strpos($string, '#')) !== false) {
396
            for ($i = $pos, $last = strrpos($string, '#', $pos) + 1; $i < $last; ++$i) {
397
                if ($string[$i] === '#') {
398
                    $toReplace[] = $i;
399
                }
400
            }
401
        }
402
 
403
        if ($nbReplacements = count($toReplace)) {
404
            $maxAtOnce = strlen((string) mt_getrandmax()) - 1;
405
            $numbers = '';
406
            $i = 0;
407
 
408
            while ($i < $nbReplacements) {
409
                $size = min($nbReplacements - $i, $maxAtOnce);
410
                $numbers .= str_pad(static::randomNumber($size), $size, '0', STR_PAD_LEFT);
411
                $i += $size;
412
            }
413
 
414
            for ($i = 0; $i < $nbReplacements; ++$i) {
415
                $string[$toReplace[$i]] = $numbers[$i];
416
            }
417
        }
418
        $string = self::replaceWildcard($string, '%', [static::class, 'randomDigitNotNull']);
419
 
420
        return $string;
421
    }
422
 
423
    /**
424
     * Replaces all question mark ('?') occurrences with a random letter
425
     *
426
     * @param string $string String that needs to bet parsed
427
     *
428
     * @return string
429
     */
430
    public static function lexify($string = '????')
431
    {
432
        return self::replaceWildcard($string, '?', [static::class,  'randomLetter']);
433
    }
434
 
435
    /**
436
     * Replaces hash signs ('#') and question marks ('?') with random numbers and letters
437
     * An asterisk ('*') is replaced with either a random number or a random letter
438
     *
439
     * @param string $string String that needs to be parsed
440
     *
441
     * @return string
442
     */
443
    public static function bothify($string = '## ??')
444
    {
445
        $string = self::replaceWildcard($string, '*', static function () {
446
            return mt_rand(0, 1) ? '#' : '?';
447
        });
448
 
449
        return static::lexify(static::numerify($string));
450
    }
451
 
452
    /**
453
     * Replaces * signs with random numbers and letters and special characters
454
     *
455
     * @example $faker->asciify(''********'); // "s5'G!uC3"
456
     *
457
     * @param string $string String that needs to bet parsed
458
     *
459
     * @return string
460
     */
461
    public static function asciify($string = '****')
462
    {
463
        return preg_replace_callback('/\*/u', [static::class, 'randomAscii'], $string);
464
    }
465
 
466
    /**
467
     * Transforms a basic regular expression into a random string satisfying the expression.
468
     *
469
     * @example $faker->regexify('[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'); // sm0@y8k96a.ej
470
     *
471
     * Regex delimiters '/.../' and begin/end markers '^...$' are ignored.
472
     *
473
     * Only supports a small subset of the regex syntax. For instance,
474
     * unicode, negated classes, unbounded ranges, subpatterns, back references,
475
     * assertions, recursive patterns, and comments are not supported. Escaping
476
     * support is extremely fragile.
477
     *
478
     * This method is also VERY slow. Use it only when no other formatter
479
     * can generate the fake data you want. For instance, prefer calling
480
     * `$faker->email` rather than `regexify` with the previous regular
481
     * expression.
482
     *
483
     * Also note than `bothify` can probably do most of what this method does,
484
     * but much faster. For instance, for a dummy email generation, try
485
     * `$faker->bothify('?????????@???.???')`.
486
     *
487
     * @see https://github.com/icomefromthenet/ReverseRegex for a more robust implementation
488
     *
489
     * @param string $regex A regular expression (delimiters are optional)
490
     *
491
     * @return string
492
     */
493
    public static function regexify($regex = '')
494
    {
495
        // ditch the anchors
496
        $regex = preg_replace('/^\/?\^?/', '', $regex);
497
        $regex = preg_replace('/\$?\/?$/', '', $regex);
498
        // All {2} become {2,2}
499
        $regex = preg_replace('/\{(\d+)\}/', '{\1,\1}', $regex);
500
        // Single-letter quantifiers (?, *, +) become bracket quantifiers ({0,1}, {0,rand}, {1, rand})
501
        $regex = preg_replace('/(?<!\\\)\?/', '{0,1}', $regex);
502
        $regex = preg_replace('/(?<!\\\)\*/', '{0,' . static::randomDigitNotNull() . '}', $regex);
503
        $regex = preg_replace('/(?<!\\\)\+/', '{1,' . static::randomDigitNotNull() . '}', $regex);
504
        // [12]{1,2} becomes [12] or [12][12]
505
        $regex = preg_replace_callback('/(\[[^\]]+\])\{(\d+),(\d+)\}/', static function ($matches) {
506
            return str_repeat($matches[1], Base::randomElement(range($matches[2], $matches[3])));
507
        }, $regex);
508
        // (12|34){1,2} becomes (12|34) or (12|34)(12|34)
509
        $regex = preg_replace_callback('/(\([^\)]+\))\{(\d+),(\d+)\}/', static function ($matches) {
510
            return str_repeat($matches[1], Base::randomElement(range($matches[2], $matches[3])));
511
        }, $regex);
512
        // A{1,2} becomes A or AA or \d{3} becomes \d\d\d
513
        $regex = preg_replace_callback('/(\\\?.)\{(\d+),(\d+)\}/', static function ($matches) {
514
            return str_repeat($matches[1], Base::randomElement(range($matches[2], $matches[3])));
515
        }, $regex);
516
        // (this|that) becomes 'this' or 'that'
517
        $regex = preg_replace_callback('/\((.*?)\)/', static function ($matches) {
518
            return Base::randomElement(explode('|', str_replace(['(', ')'], '', $matches[1])));
519
        }, $regex);
520
        // All A-F inside of [] become ABCDEF
521
        $regex = preg_replace_callback('/\[([^\]]+)\]/', static function ($matches) {
522
            return '[' . preg_replace_callback('/(\w|\d)\-(\w|\d)/', static function ($range) {
523
                return implode('', range($range[1], $range[2]));
524
            }, $matches[1]) . ']';
525
        }, $regex);
526
        // All [ABC] become B (or A or C)
527
        $regex = preg_replace_callback('/\[([^\]]+)\]/', static function ($matches) {
528
            // remove backslashes (that are not followed by another backslash) because they are escape characters
529
            $match = preg_replace('/\\\(?!\\\)/', '', $matches[1]);
530
            $randomElement = Base::randomElement(str_split($match));
531
            //[.] should not be a random character, but a literal .
532
            return str_replace('.', '\.', $randomElement);
533
        }, $regex);
534
        // replace \d with number and \w with letter and . with ascii
535
        $regex = preg_replace_callback('/\\\w/', [static::class, 'randomLetter'], $regex);
536
        $regex = preg_replace_callback('/\\\d/', [static::class, 'randomDigit'], $regex);
537
        //replace . with ascii except backslash
538
        $regex = preg_replace_callback('/(?<!\\\)\./', static function () {
539
            $chr = static::asciify('*');
540
 
541
            if ($chr === '\\') {
542
                $chr .= '\\';
543
            }
544
 
545
            return $chr;
546
        }, $regex);
547
        // remove remaining single backslashes
548
        $regex = str_replace('\\\\', '[:escaped_backslash:]', $regex);
549
        $regex = str_replace('\\', '', $regex);
550
        $regex = str_replace('[:escaped_backslash:]', '\\', $regex);
551
 
552
        // phew
553
        return $regex;
554
    }
555
 
556
    /**
557
     * Converts string to lowercase.
558
     * Uses mb_string extension if available.
559
     *
560
     * @param string $string String that should be converted to lowercase
561
     *
562
     * @return string
563
     */
564
    public static function toLower($string = '')
565
    {
566
        return extension_loaded('mbstring') ? mb_strtolower($string, 'UTF-8') : strtolower($string);
567
    }
568
 
569
    /**
570
     * Converts string to uppercase.
571
     * Uses mb_string extension if available.
572
     *
573
     * @param string $string String that should be converted to uppercase
574
     *
575
     * @return string
576
     */
577
    public static function toUpper($string = '')
578
    {
579
        return extension_loaded('mbstring') ? mb_strtoupper($string, 'UTF-8') : strtoupper($string);
580
    }
581
 
582
    /**
583
     * Chainable method for making any formatter optional.
584
     *
585
     * @param float|int $weight Set the probability of receiving a null value.
586
     *                          "0" will always return null, "1" will always return the generator.
587
     *                          If $weight is an integer value, then the same system works
588
     *                          between 0 (always get false) and 100 (always get true).
589
     *
590
     * @return mixed|null
591
     */
592
    public function optional($weight = 0.5, $default = null)
593
    {
594
        // old system based on 0.1 <= $weight <= 0.9
595
        // TODO: remove in v2
596
        if ($weight > 0 && $weight < 1 && mt_rand() / mt_getrandmax() <= $weight) {
597
            return $this->generator;
598
        }
599
 
600
        // new system with percentage
601
        if (is_int($weight) && mt_rand(1, 100) <= $weight) {
602
            return $this->generator;
603
        }
604
 
605
        return new DefaultGenerator($default);
606
    }
607
 
608
    /**
609
     * Chainable method for making any formatter unique.
610
     *
611
     * <code>
612
     * // will never return twice the same value
613
     * $faker->unique()->randomElement(array(1, 2, 3));
614
     * </code>
615
     *
616
     * @param bool $reset      If set to true, resets the list of existing values
617
     * @param int  $maxRetries Maximum number of retries to find a unique value,
618
     *                         After which an OverflowException is thrown.
619
     *
620
     * @throws \OverflowException When no unique value can be found by iterating $maxRetries times
621
     *
622
     * @return UniqueGenerator A proxy class returning only non-existing values
623
     */
624
    public function unique($reset = false, $maxRetries = 10000)
625
    {
626
        if ($reset || !$this->unique) {
627
            $this->unique = new UniqueGenerator($this->generator, $maxRetries);
628
        }
629
 
630
        return $this->unique;
631
    }
632
 
633
    /**
634
     * Chainable method for forcing any formatter to return only valid values.
635
     *
636
     * The value validity is determined by a function passed as first argument.
637
     *
638
     * <code>
639
     * $values = array();
640
     * $evenValidator = function ($digit) {
641
     *   return $digit % 2 === 0;
642
     * };
643
     * for ($i=0; $i < 10; $i++) {
644
     *   $values []= $faker->valid($evenValidator)->randomDigit;
645
     * }
646
     * print_r($values); // [0, 4, 8, 4, 2, 6, 0, 8, 8, 6]
647
     * </code>
648
     *
649
     * @param Closure $validator  A function returning true for valid values
650
     * @param int     $maxRetries Maximum number of retries to find a unique value,
651
     *                            After which an OverflowException is thrown.
652
     *
653
     * @throws \OverflowException When no valid value can be found by iterating $maxRetries times
654
     *
655
     * @return ValidGenerator A proxy class returning only valid values
656
     */
657
    public function valid($validator = null, $maxRetries = 10000)
658
    {
659
        return new ValidGenerator($this->generator, $validator, $maxRetries);
660
    }
661
}