Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Component\Utility;
|
Chris@0
|
4
|
Chris@0
|
5 /**
|
Chris@0
|
6 * Defines a utility class for creating random data.
|
Chris@0
|
7 *
|
Chris@0
|
8 * @ingroup utility
|
Chris@0
|
9 */
|
Chris@0
|
10 class Random {
|
Chris@0
|
11
|
Chris@0
|
12 /**
|
Chris@0
|
13 * The maximum number of times name() and string() can loop.
|
Chris@0
|
14 *
|
Chris@0
|
15 * This prevents infinite loops if the length of the random value is very
|
Chris@0
|
16 * small.
|
Chris@0
|
17 *
|
Chris@0
|
18 * @see \Drupal\Tests\Component\Utility\RandomTest
|
Chris@0
|
19 */
|
Chris@0
|
20 const MAXIMUM_TRIES = 100;
|
Chris@0
|
21
|
Chris@0
|
22 /**
|
Chris@0
|
23 * A list of unique strings generated by string().
|
Chris@0
|
24 *
|
Chris@0
|
25 * @var array
|
Chris@0
|
26 */
|
Chris@0
|
27 protected $strings = [];
|
Chris@0
|
28
|
Chris@0
|
29 /**
|
Chris@0
|
30 * A list of unique names generated by name().
|
Chris@0
|
31 *
|
Chris@0
|
32 * @var array
|
Chris@0
|
33 */
|
Chris@0
|
34 protected $names = [];
|
Chris@0
|
35
|
Chris@0
|
36 /**
|
Chris@0
|
37 * Generates a random string of ASCII characters of codes 32 to 126.
|
Chris@0
|
38 *
|
Chris@0
|
39 * The generated string includes alpha-numeric characters and common
|
Chris@0
|
40 * miscellaneous characters. Use this method when testing general input
|
Chris@0
|
41 * where the content is not restricted.
|
Chris@0
|
42 *
|
Chris@0
|
43 * @param int $length
|
Chris@0
|
44 * Length of random string to generate.
|
Chris@0
|
45 * @param bool $unique
|
Chris@0
|
46 * (optional) If TRUE ensures that the random string returned is unique.
|
Chris@0
|
47 * Defaults to FALSE.
|
Chris@0
|
48 * @param callable $validator
|
Chris@0
|
49 * (optional) A callable to validate the string. Defaults to NULL.
|
Chris@0
|
50 *
|
Chris@0
|
51 * @return string
|
Chris@0
|
52 * Randomly generated string.
|
Chris@0
|
53 *
|
Chris@0
|
54 * @see \Drupal\Component\Utility\Random::name()
|
Chris@0
|
55 */
|
Chris@0
|
56 public function string($length = 8, $unique = FALSE, $validator = NULL) {
|
Chris@0
|
57 $counter = 0;
|
Chris@0
|
58
|
Chris@0
|
59 // Continue to loop if $unique is TRUE and the generated string is not
|
Chris@0
|
60 // unique or if $validator is a callable that returns FALSE. To generate a
|
Chris@0
|
61 // random string this loop must be carried out at least once.
|
Chris@0
|
62 do {
|
Chris@0
|
63 if ($counter == static::MAXIMUM_TRIES) {
|
Chris@0
|
64 throw new \RuntimeException('Unable to generate a unique random name');
|
Chris@0
|
65 }
|
Chris@0
|
66 $str = '';
|
Chris@0
|
67 for ($i = 0; $i < $length; $i++) {
|
Chris@0
|
68 $str .= chr(mt_rand(32, 126));
|
Chris@0
|
69 }
|
Chris@0
|
70 $counter++;
|
Chris@0
|
71
|
Chris@0
|
72 $continue = FALSE;
|
Chris@0
|
73 if ($unique) {
|
Chris@0
|
74 $continue = isset($this->strings[$str]);
|
Chris@0
|
75 }
|
Chris@0
|
76 if (!$continue && is_callable($validator)) {
|
Chris@0
|
77 // If the validator callback returns FALSE generate another random
|
Chris@0
|
78 // string.
|
Chris@0
|
79 $continue = !call_user_func($validator, $str);
|
Chris@0
|
80 }
|
Chris@0
|
81 } while ($continue);
|
Chris@0
|
82
|
Chris@0
|
83 if ($unique) {
|
Chris@0
|
84 $this->strings[$str] = TRUE;
|
Chris@0
|
85 }
|
Chris@0
|
86
|
Chris@0
|
87 return $str;
|
Chris@0
|
88 }
|
Chris@0
|
89
|
Chris@0
|
90 /**
|
Chris@0
|
91 * Generates a random string containing letters and numbers.
|
Chris@0
|
92 *
|
Chris@0
|
93 * The string will always start with a letter. The letters may be upper or
|
Chris@0
|
94 * lower case. This method is better for restricted inputs that do not
|
Chris@0
|
95 * accept certain characters. For example, when testing input fields that
|
Chris@0
|
96 * require machine readable values (i.e. without spaces and non-standard
|
Chris@0
|
97 * characters) this method is best.
|
Chris@0
|
98 *
|
Chris@0
|
99 * @param int $length
|
Chris@0
|
100 * Length of random string to generate.
|
Chris@0
|
101 * @param bool $unique
|
Chris@0
|
102 * (optional) If TRUE ensures that the random string returned is unique.
|
Chris@0
|
103 * Defaults to FALSE.
|
Chris@0
|
104 *
|
Chris@0
|
105 * @return string
|
Chris@0
|
106 * Randomly generated string.
|
Chris@0
|
107 *
|
Chris@0
|
108 * @see \Drupal\Component\Utility\Random::string()
|
Chris@0
|
109 */
|
Chris@0
|
110 public function name($length = 8, $unique = FALSE) {
|
Chris@0
|
111 $values = array_merge(range(65, 90), range(97, 122), range(48, 57));
|
Chris@0
|
112 $max = count($values) - 1;
|
Chris@0
|
113 $counter = 0;
|
Chris@0
|
114
|
Chris@0
|
115 do {
|
Chris@0
|
116 if ($counter == static::MAXIMUM_TRIES) {
|
Chris@0
|
117 throw new \RuntimeException('Unable to generate a unique random name');
|
Chris@0
|
118 }
|
Chris@0
|
119 $str = chr(mt_rand(97, 122));
|
Chris@0
|
120 for ($i = 1; $i < $length; $i++) {
|
Chris@0
|
121 $str .= chr($values[mt_rand(0, $max)]);
|
Chris@0
|
122 }
|
Chris@0
|
123 $counter++;
|
Chris@0
|
124 } while ($unique && isset($this->names[$str]));
|
Chris@0
|
125
|
Chris@0
|
126 if ($unique) {
|
Chris@0
|
127 $this->names[$str] = TRUE;
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 return $str;
|
Chris@0
|
131 }
|
Chris@0
|
132
|
Chris@0
|
133 /**
|
Chris@0
|
134 * Generate a string that looks like a word (letters only, alternating consonants and vowels).
|
Chris@0
|
135 *
|
Chris@0
|
136 * @param int $length
|
Chris@0
|
137 * The desired word length.
|
Chris@0
|
138 *
|
Chris@0
|
139 * @return string
|
Chris@0
|
140 */
|
Chris@0
|
141 public function word($length) {
|
Chris@0
|
142 mt_srand((double) microtime() * 1000000);
|
Chris@0
|
143
|
Chris@0
|
144 $vowels = ["a", "e", "i", "o", "u"];
|
Chris@0
|
145 $cons = ["b", "c", "d", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "u", "v", "w", "tr",
|
Chris@0
|
146 "cr", "br", "fr", "th", "dr", "ch", "ph", "wr", "st", "sp", "sw", "pr",
|
Chris@0
|
147 "sl", "cl", "sh",
|
Chris@0
|
148 ];
|
Chris@0
|
149
|
Chris@0
|
150 $num_vowels = count($vowels);
|
Chris@0
|
151 $num_cons = count($cons);
|
Chris@0
|
152 $word = '';
|
Chris@0
|
153
|
Chris@0
|
154 while (strlen($word) < $length) {
|
Chris@0
|
155 $word .= $cons[mt_rand(0, $num_cons - 1)] . $vowels[mt_rand(0, $num_vowels - 1)];
|
Chris@0
|
156 }
|
Chris@0
|
157
|
Chris@0
|
158 return substr($word, 0, $length);
|
Chris@0
|
159 }
|
Chris@0
|
160
|
Chris@0
|
161 /**
|
Chris@0
|
162 * Generates a random PHP object.
|
Chris@0
|
163 *
|
Chris@0
|
164 * @param int $size
|
Chris@0
|
165 * The number of random keys to add to the object.
|
Chris@0
|
166 *
|
Chris@0
|
167 * @return \stdClass
|
Chris@0
|
168 * The generated object, with the specified number of random keys. Each key
|
Chris@0
|
169 * has a random string value.
|
Chris@0
|
170 */
|
Chris@0
|
171 public function object($size = 4) {
|
Chris@0
|
172 $object = new \stdClass();
|
Chris@0
|
173 for ($i = 0; $i < $size; $i++) {
|
Chris@0
|
174 $random_key = $this->name();
|
Chris@0
|
175 $random_value = $this->string();
|
Chris@0
|
176 $object->{$random_key} = $random_value;
|
Chris@0
|
177 }
|
Chris@0
|
178 return $object;
|
Chris@0
|
179 }
|
Chris@0
|
180
|
Chris@0
|
181 /**
|
Chris@0
|
182 * Generates sentences Latin words, often used as placeholder text.
|
Chris@0
|
183 *
|
Chris@0
|
184 * @param int $min_word_count
|
Chris@0
|
185 * The minimum number of words in the return string. Total word count
|
Chris@0
|
186 * can slightly exceed provided this value in order to deliver
|
Chris@0
|
187 * sentences of random length.
|
Chris@0
|
188 * @param bool $capitalize
|
Chris@0
|
189 * Uppercase all the words in the string.
|
Chris@0
|
190 *
|
Chris@0
|
191 * @return string
|
Chris@0
|
192 * Nonsense latin words which form sentence(s).
|
Chris@0
|
193 */
|
Chris@0
|
194 public function sentences($min_word_count, $capitalize = FALSE) {
|
Chris@0
|
195 $dictionary = ["abbas", "abdo", "abico", "abigo", "abluo", "accumsan",
|
Chris@0
|
196 "acsi", "ad", "adipiscing", "aliquam", "aliquip", "amet", "antehabeo",
|
Chris@0
|
197 "appellatio", "aptent", "at", "augue", "autem", "bene", "blandit",
|
Chris@0
|
198 "brevitas", "caecus", "camur", "capto", "causa", "cogo", "comis",
|
Chris@0
|
199 "commodo", "commoveo", "consectetuer", "consequat", "conventio", "cui",
|
Chris@0
|
200 "damnum", "decet", "defui", "diam", "dignissim", "distineo", "dolor",
|
Chris@0
|
201 "dolore", "dolus", "duis", "ea", "eligo", "elit", "enim", "erat",
|
Chris@0
|
202 "eros", "esca", "esse", "et", "eu", "euismod", "eum", "ex", "exerci",
|
Chris@0
|
203 "exputo", "facilisi", "facilisis", "fere", "feugiat", "gemino",
|
Chris@0
|
204 "genitus", "gilvus", "gravis", "haero", "hendrerit", "hos", "huic",
|
Chris@0
|
205 "humo", "iaceo", "ibidem", "ideo", "ille", "illum", "immitto",
|
Chris@0
|
206 "importunus", "imputo", "in", "incassum", "inhibeo", "interdico",
|
Chris@0
|
207 "iriure", "iusto", "iustum", "jugis", "jumentum", "jus", "laoreet",
|
Chris@0
|
208 "lenis", "letalis", "lobortis", "loquor", "lucidus", "luctus", "ludus",
|
Chris@0
|
209 "luptatum", "macto", "magna", "mauris", "melior", "metuo", "meus",
|
Chris@0
|
210 "minim", "modo", "molior", "mos", "natu", "neo", "neque", "nibh",
|
Chris@0
|
211 "nimis", "nisl", "nobis", "nostrud", "nulla", "nunc", "nutus", "obruo",
|
Chris@0
|
212 "occuro", "odio", "olim", "oppeto", "os", "pagus", "pala", "paratus",
|
Chris@0
|
213 "patria", "paulatim", "pecus", "persto", "pertineo", "plaga", "pneum",
|
Chris@0
|
214 "populus", "praemitto", "praesent", "premo", "probo", "proprius",
|
Chris@0
|
215 "quadrum", "quae", "qui", "quia", "quibus", "quidem", "quidne", "quis",
|
Chris@0
|
216 "ratis", "refero", "refoveo", "roto", "rusticus", "saepius",
|
Chris@0
|
217 "sagaciter", "saluto", "scisco", "secundum", "sed", "si", "similis",
|
Chris@0
|
218 "singularis", "sino", "sit", "sudo", "suscipere", "suscipit", "tamen",
|
Chris@0
|
219 "tation", "te", "tego", "tincidunt", "torqueo", "tum", "turpis",
|
Chris@0
|
220 "typicus", "ulciscor", "ullamcorper", "usitas", "ut", "utinam",
|
Chris@0
|
221 "utrum", "uxor", "valde", "valetudo", "validus", "vel", "velit",
|
Chris@0
|
222 "veniam", "venio", "vereor", "vero", "verto", "vicis", "vindico",
|
Chris@0
|
223 "virtus", "voco", "volutpat", "vulpes", "vulputate", "wisi", "ymo",
|
Chris@0
|
224 "zelus",
|
Chris@0
|
225 ];
|
Chris@0
|
226 $dictionary_flipped = array_flip($dictionary);
|
Chris@0
|
227 $greeking = '';
|
Chris@0
|
228
|
Chris@0
|
229 if (!$capitalize) {
|
Chris@0
|
230 $words_remaining = $min_word_count;
|
Chris@0
|
231 while ($words_remaining > 0) {
|
Chris@0
|
232 $sentence_length = mt_rand(3, 10);
|
Chris@0
|
233 $words = array_rand($dictionary_flipped, $sentence_length);
|
Chris@0
|
234 $sentence = implode(' ', $words);
|
Chris@0
|
235 $greeking .= ucfirst($sentence) . '. ';
|
Chris@0
|
236 $words_remaining -= $sentence_length;
|
Chris@0
|
237 }
|
Chris@0
|
238 }
|
Chris@0
|
239 else {
|
Chris@0
|
240 // Use slightly different method for titles.
|
Chris@0
|
241 $words = array_rand($dictionary_flipped, $min_word_count);
|
Chris@0
|
242 $words = is_array($words) ? implode(' ', $words) : $words;
|
Chris@0
|
243 $greeking = ucwords($words);
|
Chris@0
|
244 }
|
Chris@0
|
245 return trim($greeking);
|
Chris@0
|
246 }
|
Chris@0
|
247
|
Chris@0
|
248 /**
|
Chris@0
|
249 * Generate paragraphs separated by double new line.
|
Chris@0
|
250 *
|
Chris@0
|
251 * @param int $paragraph_count
|
Chris@0
|
252 * @return string
|
Chris@0
|
253 */
|
Chris@0
|
254 public function paragraphs($paragraph_count = 12) {
|
Chris@0
|
255 $output = '';
|
Chris@0
|
256 for ($i = 1; $i <= $paragraph_count; $i++) {
|
Chris@0
|
257 $output .= $this->sentences(mt_rand(20, 60)) . "\n\n";
|
Chris@0
|
258 }
|
Chris@0
|
259 return $output;
|
Chris@0
|
260 }
|
Chris@0
|
261
|
Chris@0
|
262 /**
|
Chris@0
|
263 * Create a placeholder image.
|
Chris@0
|
264 *
|
Chris@0
|
265 * @param string $destination
|
Chris@0
|
266 * The absolute file path where the image should be stored.
|
Chris@0
|
267 * @param int $min_resolution
|
Chris@0
|
268 * @param int $max_resolution
|
Chris@0
|
269 *
|
Chris@0
|
270 * @return string
|
Chris@0
|
271 * Path to image file.
|
Chris@0
|
272 */
|
Chris@0
|
273 public function image($destination, $min_resolution, $max_resolution) {
|
Chris@0
|
274 $extension = pathinfo($destination, PATHINFO_EXTENSION);
|
Chris@0
|
275 $min = explode('x', $min_resolution);
|
Chris@0
|
276 $max = explode('x', $max_resolution);
|
Chris@0
|
277
|
Chris@0
|
278 $width = rand((int) $min[0], (int) $max[0]);
|
Chris@0
|
279 $height = rand((int) $min[1], (int) $max[1]);
|
Chris@0
|
280
|
Chris@0
|
281 // Make an image split into 4 sections with random colors.
|
Chris@0
|
282 $im = imagecreate($width, $height);
|
Chris@0
|
283 for ($n = 0; $n < 4; $n++) {
|
Chris@0
|
284 $color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));
|
Chris@0
|
285 $x = $width / 2 * ($n % 2);
|
Chris@0
|
286 $y = $height / 2 * (int) ($n >= 2);
|
Chris@0
|
287 imagefilledrectangle($im, $x, $y, $x + $width / 2, $y + $height / 2, $color);
|
Chris@0
|
288 }
|
Chris@0
|
289
|
Chris@0
|
290 // Make a perfect circle in the image middle.
|
Chris@0
|
291 $color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));
|
Chris@0
|
292 $smaller_dimension = min($width, $height);
|
Chris@0
|
293 imageellipse($im, $width / 2, $height / 2, $smaller_dimension, $smaller_dimension, $color);
|
Chris@0
|
294
|
Chris@0
|
295 $save_function = 'image' . ($extension == 'jpg' ? 'jpeg' : $extension);
|
Chris@0
|
296 $save_function($im, $destination);
|
Chris@0
|
297 return $destination;
|
Chris@0
|
298 }
|
Chris@0
|
299
|
Chris@0
|
300 }
|