1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpSpreadsheet\Calculation; |
4
|
|
|
|
5
|
|
|
/* MAX_VALUE */ |
6
|
1 |
|
define('MAX_VALUE', 1.2e308); |
7
|
|
|
|
8
|
|
|
/* 2 / PI */ |
9
|
1 |
|
define('M_2DIVPI', 0.63661977236758134307553505349006); |
10
|
|
|
|
11
|
|
|
/* MAX_ITERATIONS */ |
12
|
1 |
|
define('MAX_ITERATIONS', 256); |
13
|
|
|
|
14
|
|
|
/* PRECISION */ |
15
|
1 |
|
define('PRECISION', 8.88E-016); |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Copyright (c) 2006 - 2016 PhpSpreadsheet |
19
|
|
|
* |
20
|
|
|
* This library is free software; you can redistribute it and/or |
21
|
|
|
* modify it under the terms of the GNU Lesser General Public |
22
|
|
|
* License as published by the Free Software Foundation; either |
23
|
|
|
* version 2.1 of the License, or (at your option) any later version. |
24
|
|
|
* |
25
|
|
|
* This library is distributed in the hope that it will be useful, |
26
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
27
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
28
|
|
|
* Lesser General Public License for more details. |
29
|
|
|
* |
30
|
|
|
* You should have received a copy of the GNU Lesser General Public |
31
|
|
|
* License along with this library; if not, write to the Free Software |
32
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
33
|
|
|
* |
34
|
|
|
* @category PhpSpreadsheet |
35
|
|
|
* @copyright Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet) |
36
|
|
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL |
37
|
|
|
* @version ##VERSION##, ##DATE## |
38
|
|
|
*/ |
39
|
|
|
class Functions |
40
|
|
|
{ |
41
|
|
|
/** constants */ |
42
|
|
|
const COMPATIBILITY_EXCEL = 'Excel'; |
43
|
|
|
const COMPATIBILITY_GNUMERIC = 'Gnumeric'; |
44
|
|
|
const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc'; |
45
|
|
|
|
46
|
|
|
const RETURNDATE_PHP_NUMERIC = 'P'; |
47
|
|
|
const RETURNDATE_PHP_OBJECT = 'O'; |
48
|
|
|
const RETURNDATE_EXCEL = 'E'; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Compatibility mode to use for error checking and responses |
52
|
|
|
* |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
protected static $compatibilityMode = self::COMPATIBILITY_EXCEL; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Data Type to use when returning date values |
59
|
|
|
* |
60
|
|
|
* @var string |
61
|
|
|
*/ |
62
|
|
|
protected static $returnDateType = self::RETURNDATE_EXCEL; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* List of error codes |
66
|
|
|
* |
67
|
|
|
* @var array |
68
|
|
|
*/ |
69
|
|
|
protected static $errorCodes = [ |
70
|
|
|
'null' => '#NULL!', |
71
|
|
|
'divisionbyzero' => '#DIV/0!', |
72
|
|
|
'value' => '#VALUE!', |
73
|
|
|
'reference' => '#REF!', |
74
|
|
|
'name' => '#NAME?', |
75
|
|
|
'num' => '#NUM!', |
76
|
|
|
'na' => '#N/A', |
77
|
|
|
'gettingdata' => '#GETTING_DATA', |
78
|
|
|
]; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Set the Compatibility Mode |
82
|
|
|
* |
83
|
|
|
* @category Function Configuration |
84
|
|
|
* @param string $compatibilityMode Compatibility Mode |
85
|
|
|
* Permitted values are: |
86
|
|
|
* Functions::COMPATIBILITY_EXCEL 'Excel' |
87
|
|
|
* Functions::COMPATIBILITY_GNUMERIC 'Gnumeric' |
88
|
|
|
* Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc' |
89
|
|
|
* @return bool (Success or Failure) |
90
|
|
|
*/ |
91
|
|
|
public static function setCompatibilityMode($compatibilityMode) |
92
|
|
|
{ |
93
|
|
|
if (($compatibilityMode == self::COMPATIBILITY_EXCEL) || |
94
|
|
|
($compatibilityMode == self::COMPATIBILITY_GNUMERIC) || |
95
|
|
|
($compatibilityMode == self::COMPATIBILITY_OPENOFFICE) |
96
|
|
|
) { |
97
|
|
|
self::$compatibilityMode = $compatibilityMode; |
98
|
2974 |
|
|
99
|
|
|
return true; |
100
|
2974 |
|
} |
101
|
52 |
|
|
102
|
2974 |
|
return false; |
103
|
|
|
} |
104
|
2974 |
|
|
105
|
2974 |
|
/** |
106
|
|
|
* Return the current Compatibility Mode |
107
|
|
|
* |
108
|
|
|
* @category Function Configuration |
109
|
|
|
* @return string Compatibility Mode |
110
|
|
|
* Possible Return values are: |
111
|
|
|
* Functions::COMPATIBILITY_EXCEL 'Excel' |
112
|
|
|
* Functions::COMPATIBILITY_GNUMERIC 'Gnumeric' |
113
|
|
|
* Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc' |
114
|
|
|
*/ |
115
|
|
|
public static function getCompatibilityMode() |
116
|
|
|
{ |
117
|
|
|
return self::$compatibilityMode; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object) |
122
|
441 |
|
* |
123
|
|
|
* @category Function Configuration |
124
|
441 |
|
* @param string $returnDateType Return Date Format |
125
|
|
|
* Permitted values are: |
126
|
|
|
* Functions::RETURNDATE_PHP_NUMERIC 'P' |
127
|
|
|
* Functions::RETURNDATE_PHP_OBJECT 'O' |
128
|
|
|
* Functions::RETURNDATE_EXCEL 'E' |
129
|
|
|
* @return bool Success or failure |
130
|
|
|
*/ |
131
|
|
|
public static function setReturnDateType($returnDateType) |
132
|
|
|
{ |
133
|
|
|
if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) || |
134
|
|
|
($returnDateType == self::RETURNDATE_PHP_OBJECT) || |
135
|
|
|
($returnDateType == self::RETURNDATE_EXCEL) |
136
|
|
|
) { |
137
|
|
|
self::$returnDateType = $returnDateType; |
138
|
|
|
|
139
|
|
|
return true; |
140
|
165 |
|
} |
141
|
|
|
|
142
|
165 |
|
return false; |
143
|
165 |
|
} |
144
|
165 |
|
|
145
|
|
|
/** |
146
|
165 |
|
* Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object) |
147
|
165 |
|
* |
148
|
|
|
* @category Function Configuration |
149
|
|
|
* @return string Return Date Format |
150
|
|
|
* Possible Return values are: |
151
|
|
|
* Functions::RETURNDATE_PHP_NUMERIC 'P' |
152
|
|
|
* Functions::RETURNDATE_PHP_OBJECT 'O' |
153
|
|
|
* Functions::RETURNDATE_EXCEL 'E' |
154
|
|
|
*/ |
155
|
|
|
public static function getReturnDateType() |
156
|
|
|
{ |
157
|
|
|
return self::$returnDateType; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* DUMMY |
162
|
|
|
* |
163
|
|
|
* @category Error Returns |
164
|
328 |
|
* @return string #Not Yet Implemented |
165
|
|
|
*/ |
166
|
328 |
|
public static function DUMMY() |
167
|
|
|
{ |
168
|
|
|
return '#Not Yet Implemented'; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* DIV0 |
173
|
|
|
* |
174
|
|
|
* @category Error Returns |
175
|
|
|
* @return string #Not Yet Implemented |
176
|
|
|
*/ |
177
|
1 |
|
public static function DIV0() |
178
|
|
|
{ |
179
|
1 |
|
return self::$errorCodes['divisionbyzero']; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* NA |
184
|
|
|
* |
185
|
|
|
* Excel Function: |
186
|
|
|
* =NA() |
187
|
|
|
* |
188
|
|
|
* Returns the error value #N/A |
189
|
|
|
* #N/A is the error value that means "no value is available." |
190
|
10 |
|
* |
191
|
|
|
* @category Logical Functions |
192
|
10 |
|
* @return string #N/A! |
193
|
|
|
*/ |
194
|
|
|
public static function NA() |
195
|
|
|
{ |
196
|
|
|
return self::$errorCodes['na']; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* NaN |
201
|
|
|
* |
202
|
|
|
* Returns the error value #NUM! |
203
|
|
|
* |
204
|
|
|
* @category Error Returns |
205
|
|
|
* @return string #NUM! |
206
|
|
|
*/ |
207
|
|
|
public static function NAN() |
208
|
|
|
{ |
209
|
36 |
|
return self::$errorCodes['num']; |
210
|
|
|
} |
211
|
36 |
|
|
212
|
|
|
/** |
213
|
|
|
* NAME |
214
|
|
|
* |
215
|
|
|
* Returns the error value #NAME? |
216
|
|
|
* |
217
|
|
|
* @category Error Returns |
218
|
|
|
* @return string #NAME? |
219
|
|
|
*/ |
220
|
|
|
public static function NAME() |
221
|
|
|
{ |
222
|
|
|
return self::$errorCodes['name']; |
223
|
|
|
} |
224
|
163 |
|
|
225
|
|
|
/** |
226
|
163 |
|
* REF |
227
|
|
|
* |
228
|
|
|
* Returns the error value #REF! |
229
|
|
|
* |
230
|
|
|
* @category Error Returns |
231
|
|
|
* @return string #REF! |
232
|
|
|
*/ |
233
|
|
|
public static function REF() |
234
|
|
|
{ |
235
|
|
|
return self::$errorCodes['reference']; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
5 |
|
* NULL |
240
|
|
|
* |
241
|
5 |
|
* Returns the error value #NULL! |
242
|
|
|
* |
243
|
|
|
* @category Error Returns |
244
|
|
|
* @return string #NULL! |
245
|
|
|
*/ |
246
|
|
|
public static function null() |
247
|
|
|
{ |
248
|
|
|
return self::$errorCodes['null']; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* VALUE |
253
|
|
|
* |
254
|
1 |
|
* Returns the error value #VALUE! |
255
|
|
|
* |
256
|
1 |
|
* @category Error Returns |
257
|
|
|
* @return string #VALUE! |
258
|
|
|
*/ |
259
|
|
|
public static function VALUE() |
260
|
|
|
{ |
261
|
|
|
return self::$errorCodes['value']; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
public static function isMatrixValue($idx) |
265
|
|
|
{ |
266
|
|
|
return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0); |
267
|
|
|
} |
268
|
|
|
|
269
|
1 |
|
public static function isValue($idx) |
270
|
|
|
{ |
271
|
1 |
|
return substr_count($idx, '.') == 0; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
public static function isCellValue($idx) |
275
|
|
|
{ |
276
|
|
|
return substr_count($idx, '.') > 1; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
public static function ifCondition($condition) |
280
|
|
|
{ |
281
|
|
|
$condition = self::flattenSingleValue($condition); |
282
|
|
|
if (!isset($condition{0})) { |
283
|
|
|
$condition = '=""'; |
284
|
167 |
|
} |
285
|
|
|
if (!in_array($condition{0}, ['>', '<', '='])) { |
286
|
167 |
|
if (!is_numeric($condition)) { |
287
|
|
|
$condition = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($condition)); |
288
|
|
|
} |
289
|
|
|
|
290
|
3 |
|
return '=' . $condition; |
291
|
|
|
} else { |
292
|
3 |
|
preg_match('/([<>=]+)(.*)/', $condition, $matches); |
293
|
|
|
list(, $operator, $operand) = $matches; |
294
|
|
|
|
295
|
|
|
if (!is_numeric($operand)) { |
296
|
|
|
$operand = str_replace('"', '""', $operand); |
297
|
|
|
$operand = \PhpSpreadsheet\Calculation::wrapResult(strtoupper($operand)); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
return $operator . $operand; |
301
|
|
|
} |
302
|
3 |
|
} |
303
|
|
|
|
304
|
3 |
|
/** |
305
|
|
|
* ERROR_TYPE |
306
|
|
|
* |
307
|
|
|
* @param mixed $value Value to check |
308
|
5 |
|
* @return bool |
309
|
|
|
*/ |
310
|
5 |
|
public static function errorType($value = '') |
311
|
5 |
|
{ |
312
|
|
|
$value = self::flattenSingleValue($value); |
313
|
|
|
|
314
|
5 |
|
$i = 1; |
315
|
|
|
foreach (self::$errorCodes as $errorCode) { |
316
|
|
|
if ($value === $errorCode) { |
317
|
|
|
return $i; |
318
|
|
|
} |
319
|
|
|
++$i; |
320
|
5 |
|
} |
321
|
5 |
|
|
322
|
|
|
return self::NA(); |
323
|
5 |
|
} |
324
|
4 |
|
|
325
|
4 |
|
/** |
326
|
|
|
* IS_BLANK |
327
|
|
|
* |
328
|
5 |
|
* @param mixed $value Value to check |
329
|
|
|
* @return bool |
330
|
|
|
*/ |
331
|
|
|
public static function isBlank($value = null) |
332
|
|
|
{ |
333
|
|
|
if (!is_null($value)) { |
334
|
|
|
$value = self::flattenSingleValue($value); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
return is_null($value); |
338
|
14 |
|
} |
339
|
|
|
|
340
|
14 |
|
/** |
341
|
|
|
* IS_ERR |
342
|
14 |
|
* |
343
|
14 |
|
* @param mixed $value Value to check |
344
|
14 |
|
* @return bool |
345
|
7 |
|
*/ |
346
|
|
|
public static function isErr($value = '') |
347
|
13 |
|
{ |
348
|
|
|
$value = self::flattenSingleValue($value); |
349
|
7 |
|
|
350
|
|
|
return self::isError($value) && (!self::isNa(($value))); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* IS_ERROR |
355
|
|
|
* |
356
|
|
|
* @param mixed $value Value to check |
357
|
|
|
* @return bool |
358
|
|
|
*/ |
359
|
16 |
|
public static function isError($value = '') |
360
|
|
|
{ |
361
|
16 |
|
$value = self::flattenSingleValue($value); |
362
|
14 |
|
|
363
|
|
|
if (!is_string($value)) { |
364
|
|
|
return false; |
365
|
16 |
|
} |
366
|
|
|
|
367
|
|
|
return in_array($value, array_values(self::$errorCodes)); |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
/** |
371
|
|
|
* IS_NA |
372
|
|
|
* |
373
|
|
|
* @param mixed $value Value to check |
374
|
|
|
* @return bool |
375
|
16 |
|
*/ |
376
|
|
|
public static function isNa($value = '') |
377
|
16 |
|
{ |
378
|
|
|
$value = self::flattenSingleValue($value); |
379
|
16 |
|
|
380
|
|
|
return $value === self::NA(); |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
/** |
384
|
|
|
* IS_EVEN |
385
|
|
|
* |
386
|
|
|
* @param mixed $value Value to check |
387
|
|
|
* @return bool |
388
|
|
|
*/ |
389
|
56 |
View Code Duplication |
public static function isEven($value = null) |
|
|
|
|
390
|
|
|
{ |
391
|
56 |
|
$value = self::flattenSingleValue($value); |
392
|
|
|
|
393
|
56 |
|
if ($value === null) { |
394
|
16 |
|
return self::NAME(); |
395
|
|
|
} elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { |
396
|
40 |
|
return self::VALUE(); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
return $value % 2 == 0; |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
/** |
403
|
|
|
* IS_ODD |
404
|
|
|
* |
405
|
|
|
* @param mixed $value Value to check |
406
|
18 |
|
* @return bool |
407
|
|
|
*/ |
408
|
18 |
View Code Duplication |
public static function isOdd($value = null) |
|
|
|
|
409
|
|
|
{ |
410
|
18 |
|
$value = self::flattenSingleValue($value); |
411
|
|
|
|
412
|
|
|
if ($value === null) { |
413
|
|
|
return self::NAME(); |
414
|
|
|
} elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { |
415
|
|
|
return self::VALUE(); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
return abs($value) % 2 == 1; |
419
|
|
|
} |
420
|
20 |
|
|
421
|
|
|
/** |
422
|
20 |
|
* IS_NUMBER |
423
|
|
|
* |
424
|
20 |
|
* @param mixed $value Value to check |
425
|
2 |
|
* @return bool |
426
|
18 |
|
*/ |
427
|
7 |
|
public static function isNumber($value = null) |
428
|
|
|
{ |
429
|
|
|
$value = self::flattenSingleValue($value); |
430
|
11 |
|
|
431
|
|
|
if (is_string($value)) { |
432
|
|
|
return false; |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
return is_numeric($value); |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* IS_LOGICAL |
440
|
20 |
|
* |
441
|
|
|
* @param mixed $value Value to check |
442
|
20 |
|
* @return bool |
443
|
|
|
*/ |
444
|
20 |
|
public static function isLogical($value = null) |
445
|
2 |
|
{ |
446
|
18 |
|
$value = self::flattenSingleValue($value); |
447
|
7 |
|
|
448
|
|
|
return is_bool($value); |
449
|
|
|
} |
450
|
11 |
|
|
451
|
|
|
/** |
452
|
|
|
* IS_TEXT |
453
|
|
|
* |
454
|
|
|
* @param mixed $value Value to check |
455
|
|
|
* @return bool |
456
|
|
|
*/ |
457
|
|
|
public static function isText($value = null) |
458
|
|
|
{ |
459
|
|
|
$value = self::flattenSingleValue($value); |
460
|
16 |
|
|
461
|
|
|
return is_string($value) && !self::isError($value); |
462
|
16 |
|
} |
463
|
|
|
|
464
|
16 |
|
/** |
465
|
8 |
|
* IS_NONTEXT |
466
|
|
|
* |
467
|
8 |
|
* @param mixed $value Value to check |
468
|
|
|
* @return bool |
469
|
|
|
*/ |
470
|
|
|
public static function isNonText($value = null) |
471
|
|
|
{ |
472
|
|
|
return !self::isText($value); |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
/** |
476
|
|
|
* VERSION |
477
|
16 |
|
* |
478
|
|
|
* @return string Version information |
479
|
16 |
|
*/ |
480
|
|
|
public static function VERSION() |
481
|
16 |
|
{ |
482
|
|
|
return 'PhpSpreadsheet ##VERSION##, ##DATE##'; |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* N |
487
|
|
|
* |
488
|
|
|
* Returns a value converted to a number |
489
|
|
|
* |
490
|
|
|
* @param value The value you want converted |
491
|
32 |
|
* @return number N converts values listed in the following table |
492
|
|
|
* If value is or refers to N returns |
493
|
32 |
|
* A number That number |
494
|
|
|
* A date The serial number of that date |
495
|
32 |
|
* TRUE 1 |
496
|
|
|
* FALSE 0 |
497
|
|
|
* An error value The error value |
498
|
|
|
* Anything else 0 |
499
|
|
|
*/ |
500
|
|
|
public static function n($value = null) |
501
|
|
|
{ |
502
|
|
|
while (is_array($value)) { |
503
|
|
|
$value = array_shift($value); |
504
|
|
|
} |
505
|
16 |
|
|
506
|
|
|
switch (gettype($value)) { |
507
|
16 |
|
case 'double': |
508
|
|
|
case 'float': |
509
|
|
|
case 'integer': |
510
|
|
|
return $value; |
511
|
|
|
case 'boolean': |
512
|
|
|
return (integer) $value; |
513
|
|
|
case 'string': |
514
|
|
|
// Errors |
515
|
|
|
if ((strlen($value) > 0) && ($value{0} == '#')) { |
516
|
|
|
return $value; |
517
|
|
|
} |
518
|
|
|
break; |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
return 0; |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
/** |
525
|
|
|
* TYPE |
526
|
|
|
* |
527
|
|
|
* Returns a number that identifies the type of a value |
528
|
|
|
* |
529
|
|
|
* @param value The value you want tested |
530
|
|
|
* @return number N converts values listed in the following table |
531
|
|
|
* If value is or refers to N returns |
532
|
|
|
* A number 1 |
533
|
|
|
* Text 2 |
534
|
|
|
* Logical Value 4 |
535
|
|
|
* An error value 16 |
536
|
|
|
* Array or Matrix 64 |
537
|
20 |
|
*/ |
538
|
|
|
public static function TYPE($value = null) |
539
|
20 |
|
{ |
540
|
9 |
|
$value = self::flattenArrayIndexed($value); |
|
|
|
|
541
|
|
|
if (is_array($value) && (count($value) > 1)) { |
542
|
|
|
end($value); |
543
|
20 |
|
$a = key($value); |
544
|
20 |
|
// Range of cells is an error |
545
|
19 |
|
if (self::isCellValue($a)) { |
546
|
19 |
|
return 16; |
547
|
8 |
|
// Test for Matrix |
548
|
12 |
|
} elseif (self::isMatrixValue($a)) { |
549
|
1 |
|
return 64; |
550
|
11 |
|
} |
551
|
|
|
} elseif (empty($value)) { |
552
|
8 |
|
// Empty Cell |
553
|
2 |
|
return 1; |
554
|
|
|
} |
555
|
6 |
|
$value = self::flattenSingleValue($value); |
556
|
|
|
|
557
|
9 |
|
if (($value === null) || (is_float($value)) || (is_int($value))) { |
558
|
|
|
return 1; |
559
|
|
|
} elseif (is_bool($value)) { |
560
|
|
|
return 4; |
561
|
|
|
} elseif (is_array($value)) { |
562
|
|
|
return 64; |
563
|
|
|
} elseif (is_string($value)) { |
564
|
|
|
// Errors |
565
|
|
|
if ((strlen($value) > 0) && ($value{0} == '#')) { |
566
|
|
|
return 16; |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
return 2; |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
return 0; |
573
|
|
|
} |
574
|
|
|
|
575
|
16 |
|
/** |
576
|
|
|
* Convert a multi-dimensional array to a simple 1-dimensional array |
577
|
16 |
|
* |
578
|
16 |
|
* @param array $array Array to be flattened |
579
|
3 |
|
* @return array Flattened array |
580
|
3 |
|
*/ |
581
|
|
|
public static function flattenArray($array) |
582
|
3 |
|
{ |
583
|
|
|
if (!is_array($array)) { |
584
|
|
|
return (array) $array; |
585
|
3 |
|
} |
586
|
3 |
|
|
587
|
|
|
$arrayValues = []; |
588
|
|
|
foreach ($array as $value) { |
589
|
|
|
if (is_array($value)) { |
590
|
2 |
|
foreach ($value as $val) { |
591
|
|
|
if (is_array($val)) { |
592
|
11 |
|
foreach ($val as $v) { |
593
|
|
|
$arrayValues[] = $v; |
594
|
11 |
|
} |
595
|
4 |
|
} else { |
596
|
7 |
|
$arrayValues[] = $val; |
597
|
1 |
|
} |
598
|
6 |
|
} |
599
|
|
|
} else { |
600
|
6 |
|
$arrayValues[] = $value; |
601
|
|
|
} |
602
|
6 |
|
} |
603
|
2 |
|
|
604
|
|
|
return $arrayValues; |
605
|
4 |
|
} |
606
|
|
|
|
607
|
|
|
/** |
608
|
|
|
* Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing |
609
|
|
|
* |
610
|
|
|
* @param array $array Array to be flattened |
611
|
|
|
* @return array Flattened array |
612
|
|
|
*/ |
613
|
|
|
public static function flattenArrayIndexed($array) |
614
|
|
|
{ |
615
|
|
|
if (!is_array($array)) { |
616
|
|
|
return (array) $array; |
617
|
234 |
|
} |
618
|
|
|
|
619
|
234 |
|
$arrayValues = []; |
620
|
|
|
foreach ($array as $k1 => $value) { |
621
|
|
|
if (is_array($value)) { |
622
|
|
|
foreach ($value as $k2 => $val) { |
623
|
234 |
|
if (is_array($val)) { |
624
|
234 |
|
foreach ($val as $k3 => $v) { |
625
|
232 |
|
$arrayValues[$k1 . '.' . $k2 . '.' . $k3] = $v; |
626
|
22 |
|
} |
627
|
22 |
|
} else { |
628
|
5 |
|
$arrayValues[$k1 . '.' . $k2] = $val; |
629
|
5 |
|
} |
630
|
|
|
} |
631
|
|
|
} else { |
632
|
22 |
|
$arrayValues[$k1] = $value; |
633
|
|
|
} |
634
|
|
|
} |
635
|
|
|
|
636
|
232 |
|
return $arrayValues; |
637
|
|
|
} |
638
|
|
|
|
639
|
|
|
/** |
640
|
234 |
|
* Convert an array to a single scalar value by extracting the first element |
641
|
|
|
* |
642
|
|
|
* @param mixed $value Array or scalar value |
643
|
|
|
* @return mixed |
644
|
|
|
*/ |
645
|
|
|
public static function flattenSingleValue($value = '') |
646
|
|
|
{ |
647
|
|
|
while (is_array($value)) { |
648
|
|
|
$value = array_pop($value); |
649
|
|
|
} |
650
|
16 |
|
|
651
|
|
|
return $value; |
652
|
16 |
|
} |
653
|
11 |
|
} |
654
|
|
|
|
655
|
|
|
// |
656
|
5 |
|
// There are a few mathematical functions that aren't available on all versions of PHP for all platforms |
657
|
5 |
|
// These functions aren't available in Windows implementations of PHP prior to version 5.3.0 |
658
|
5 |
|
// So we test if they do exist for this version of PHP/operating platform; and if not we create them |
659
|
2 |
|
// |
660
|
2 |
|
if (!function_exists('acosh')) { |
661
|
|
|
function acosh($x) |
662
|
|
|
{ |
663
|
|
|
return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2)); |
664
|
|
|
} // function acosh() |
|
|
|
|
665
|
2 |
|
} |
666
|
|
|
|
667
|
|
|
if (!function_exists('asinh')) { |
668
|
|
|
function asinh($x) |
669
|
5 |
|
{ |
670
|
|
|
return log($x + sqrt(1 + $x * $x)); |
671
|
|
|
} // function asinh() |
|
|
|
|
672
|
|
|
} |
673
|
5 |
|
|
674
|
|
|
if (!function_exists('atanh')) { |
675
|
|
|
function atanh($x) |
676
|
|
|
{ |
677
|
|
|
return (log(1 + $x) - log(1 - $x)) / 2; |
678
|
|
|
} // function atanh() |
|
|
|
|
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
// |
682
|
|
|
// Strangely, PHP doesn't have a mb_str_replace multibyte function |
683
|
2821 |
|
// As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set |
684
|
|
|
// |
685
|
2821 |
|
if ((!function_exists('mb_str_replace')) && |
686
|
11 |
|
(function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos')) |
687
|
|
|
) { |
688
|
|
|
function mb_str_replace($search, $replace, $subject) |
689
|
2821 |
|
{ |
690
|
|
|
if (is_array($subject)) { |
691
|
|
|
$ret = []; |
692
|
|
|
foreach ($subject as $key => $val) { |
693
|
|
|
$ret[$key] = mb_str_replace($search, $replace, $val); |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
return $ret; |
697
|
|
|
} |
698
|
|
|
|
699
|
1 |
|
foreach ((array) $search as $key => $s) { |
700
|
|
|
if ($s == '' && $s !== 0) { |
701
|
|
|
continue; |
702
|
|
|
} |
703
|
|
|
$r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : ''); |
704
|
|
|
$pos = mb_strpos($subject, $s, 0, 'UTF-8'); |
705
|
|
|
while ($pos !== false) { |
706
|
1 |
|
$subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8'); |
707
|
|
|
$pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8'); |
708
|
|
|
} |
709
|
|
|
} |
710
|
|
|
|
711
|
|
|
return $subject; |
712
|
|
|
} |
713
|
|
|
} |
714
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.