Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
 
5
use PhpOffice\PhpSpreadsheet\Cell\Cell;
6
use PhpOffice\PhpSpreadsheet\Shared\Date;
7
 
8
class Functions
9
{
10
    const PRECISION = 8.88E-016;
11
 
12
    /**
13
     * 2 / PI.
14
     */
15
    const M_2DIVPI = 0.63661977236758134307553505349006;
16
 
17
    const COMPATIBILITY_EXCEL = 'Excel';
18
    const COMPATIBILITY_GNUMERIC = 'Gnumeric';
19
    const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
20
 
21
    /** Use of RETURNDATE_PHP_NUMERIC is discouraged - not 32-bit Y2038-safe, no timezone. */
22
    const RETURNDATE_PHP_NUMERIC = 'P';
23
    /** Use of RETURNDATE_UNIX_TIMESTAMP is discouraged - not 32-bit Y2038-safe, no timezone. */
24
    const RETURNDATE_UNIX_TIMESTAMP = 'P';
25
    const RETURNDATE_PHP_OBJECT = 'O';
26
    const RETURNDATE_PHP_DATETIME_OBJECT = 'O';
27
    const RETURNDATE_EXCEL = 'E';
28
 
29
    /**
30
     * Compatibility mode to use for error checking and responses.
31
     *
32
     * @var string
33
     */
34
    protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
35
 
36
    /**
37
     * Data Type to use when returning date values.
38
     *
39
     * @var string
40
     */
41
    protected static $returnDateType = self::RETURNDATE_EXCEL;
42
 
43
    /**
44
     * Set the Compatibility Mode.
45
     *
46
     * @param string $compatibilityMode Compatibility Mode
47
     *                                  Permitted values are:
48
     *                                      Functions::COMPATIBILITY_EXCEL        'Excel'
49
     *                                      Functions::COMPATIBILITY_GNUMERIC     'Gnumeric'
50
     *                                      Functions::COMPATIBILITY_OPENOFFICE   'OpenOfficeCalc'
51
     *
52
     * @return bool (Success or Failure)
53
     */
54
    public static function setCompatibilityMode($compatibilityMode)
55
    {
56
        if (
57
            ($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
58
            ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
59
            ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)
60
        ) {
61
            self::$compatibilityMode = $compatibilityMode;
62
 
63
            return true;
64
        }
65
 
66
        return false;
67
    }
68
 
69
    /**
70
     * Return the current Compatibility Mode.
71
     *
72
     * @return string Compatibility Mode
73
     *                Possible Return values are:
74
     *                    Functions::COMPATIBILITY_EXCEL        'Excel'
75
     *                    Functions::COMPATIBILITY_GNUMERIC     'Gnumeric'
76
     *                    Functions::COMPATIBILITY_OPENOFFICE   'OpenOfficeCalc'
77
     */
78
    public static function getCompatibilityMode()
79
    {
80
        return self::$compatibilityMode;
81
    }
82
 
83
    /**
84
     * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP DateTime Object).
85
     *
86
     * @param string $returnDateType Return Date Format
87
     *                               Permitted values are:
88
     *                                   Functions::RETURNDATE_UNIX_TIMESTAMP       'P'
89
     *                                   Functions::RETURNDATE_PHP_DATETIME_OBJECT  'O'
90
     *                                   Functions::RETURNDATE_EXCEL                'E'
91
     *
92
     * @return bool Success or failure
93
     */
94
    public static function setReturnDateType($returnDateType)
95
    {
96
        if (
97
            ($returnDateType == self::RETURNDATE_UNIX_TIMESTAMP) ||
98
            ($returnDateType == self::RETURNDATE_PHP_DATETIME_OBJECT) ||
99
            ($returnDateType == self::RETURNDATE_EXCEL)
100
        ) {
101
            self::$returnDateType = $returnDateType;
102
 
103
            return true;
104
        }
105
 
106
        return false;
107
    }
108
 
109
    /**
110
     * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object).
111
     *
112
     * @return string Return Date Format
113
     *                Possible Return values are:
114
     *                    Functions::RETURNDATE_UNIX_TIMESTAMP         'P'
115
     *                    Functions::RETURNDATE_PHP_DATETIME_OBJECT    'O'
116
     *                    Functions::RETURNDATE_EXCEL            '     'E'
117
     */
118
    public static function getReturnDateType()
119
    {
120
        return self::$returnDateType;
121
    }
122
 
123
    /**
124
     * DUMMY.
125
     *
126
     * @return string #Not Yet Implemented
127
     */
128
    public static function DUMMY()
129
    {
130
        return '#Not Yet Implemented';
131
    }
132
 
133
    /** @param mixed $idx */
134
    public static function isMatrixValue($idx): bool
135
    {
136
        return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0);
137
    }
138
 
139
    /** @param mixed $idx */
140
    public static function isValue($idx): bool
141
    {
142
        return substr_count($idx, '.') === 0;
143
    }
144
 
145
    /** @param mixed $idx */
146
    public static function isCellValue($idx): bool
147
    {
148
        return substr_count($idx, '.') > 1;
149
    }
150
 
151
    /** @param mixed $condition */
152
    public static function ifCondition($condition): string
153
    {
154
        $condition = self::flattenSingleValue($condition);
155
 
156
        if ($condition === '') {
157
            return '=""';
158
        }
159
        if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='], true)) {
160
            $condition = self::operandSpecialHandling($condition);
161
            if (is_bool($condition)) {
162
                return '=' . ($condition ? 'TRUE' : 'FALSE');
163
            } elseif (!is_numeric($condition)) {
164
                if ($condition !== '""') { // Not an empty string
165
                    // Escape any quotes in the string value
166
                    $condition = (string) preg_replace('/"/ui', '""', $condition);
167
                }
168
                $condition = Calculation::wrapResult(strtoupper($condition));
169
            }
170
 
171
            return str_replace('""""', '""', '=' . $condition);
172
        }
173
        preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches);
174
        [, $operator, $operand] = $matches;
175
 
176
        $operand = self::operandSpecialHandling($operand);
177
        if (is_numeric(trim($operand, '"'))) {
178
            $operand = trim($operand, '"');
179
        } elseif (!is_numeric($operand) && $operand !== 'FALSE' && $operand !== 'TRUE') {
180
            $operand = str_replace('"', '""', $operand);
181
            $operand = Calculation::wrapResult(strtoupper($operand));
182
        }
183
 
184
        return str_replace('""""', '""', $operator . $operand);
185
    }
186
 
187
    /**
188
     * @param mixed $operand
189
     *
190
     * @return mixed
191
     */
192
    private static function operandSpecialHandling($operand)
193
    {
194
        if (is_numeric($operand) || is_bool($operand)) {
195
            return $operand;
196
        } elseif (strtoupper($operand) === Calculation::getTRUE() || strtoupper($operand) === Calculation::getFALSE()) {
197
            return strtoupper($operand);
198
        }
199
 
200
        // Check for percentage
201
        if (preg_match('/^\-?\d*\.?\d*\s?\%$/', $operand)) {
202
            return ((float) rtrim($operand, '%')) / 100;
203
        }
204
 
205
        // Check for dates
206
        if (($dateValueOperand = Date::stringToExcel($operand)) !== false) {
207
            return $dateValueOperand;
208
        }
209
 
210
        return $operand;
211
    }
212
 
213
    /**
214
     * NULL.
215
     *
216
     * Returns the error value #NULL!
217
     *
218
     * @deprecated 1.23.0 Use the null() method in the Information\ExcelError class instead
219
     * @see Information\ExcelError::null()
220
     *
221
     * @return string #NULL!
222
     */
223
    public static function null()
224
    {
225
        return Information\ExcelError::null();
226
    }
227
 
228
    /**
229
     * NaN.
230
     *
231
     * Returns the error value #NUM!
232
     *
233
     * @deprecated 1.23.0 Use the NAN() method in the Information\Error class instead
234
     * @see Information\ExcelError::NAN()
235
     *
236
     * @return string #NUM!
237
     */
238
    public static function NAN()
239
    {
240
        return Information\ExcelError::NAN();
241
    }
242
 
243
    /**
244
     * REF.
245
     *
246
     * Returns the error value #REF!
247
     *
248
     * @deprecated 1.23.0 Use the REF() method in the Information\ExcelError class instead
249
     * @see Information\ExcelError::REF()
250
     *
251
     * @return string #REF!
252
     */
253
    public static function REF()
254
    {
255
        return Information\ExcelError::REF();
256
    }
257
 
258
    /**
259
     * NA.
260
     *
261
     * Excel Function:
262
     *        =NA()
263
     *
264
     * Returns the error value #N/A
265
     *        #N/A is the error value that means "no value is available."
266
     *
267
     * @deprecated 1.23.0 Use the NA() method in the Information\ExcelError class instead
268
     * @see Information\ExcelError::NA()
269
     *
270
     * @return string #N/A!
271
     */
272
    public static function NA()
273
    {
274
        return Information\ExcelError::NA();
275
    }
276
 
277
    /**
278
     * VALUE.
279
     *
280
     * Returns the error value #VALUE!
281
     *
282
     * @deprecated 1.23.0 Use the VALUE() method in the Information\ExcelError class instead
283
     * @see Information\ExcelError::VALUE()
284
     *
285
     * @return string #VALUE!
286
     */
287
    public static function VALUE()
288
    {
289
        return Information\ExcelError::VALUE();
290
    }
291
 
292
    /**
293
     * NAME.
294
     *
295
     * Returns the error value #NAME?
296
     *
297
     * @deprecated 1.23.0 Use the NAME() method in the Information\ExcelError class instead
298
     * @see Information\ExcelError::NAME()
299
     *
300
     * @return string #NAME?
301
     */
302
    public static function NAME()
303
    {
304
        return Information\ExcelError::NAME();
305
    }
306
 
307
    /**
308
     * DIV0.
309
     *
310
     * @deprecated 1.23.0 Use the DIV0() method in the Information\ExcelError class instead
311
     * @see Information\ExcelError::DIV0()
312
     *
313
     * @return string #Not Yet Implemented
314
     */
315
    public static function DIV0()
316
    {
317
        return Information\ExcelError::DIV0();
318
    }
319
 
320
    /**
321
     * ERROR_TYPE.
322
     *
323
     * @param mixed $value Value to check
324
     *
325
     * @deprecated 1.23.0 Use the type() method in the Information\ExcelError class instead
326
     * @see Information\ExcelError::type()
327
     *
328
     * @return array|int|string
329
     */
330
    public static function errorType($value = '')
331
    {
332
        return Information\ExcelError::type($value);
333
    }
334
 
335
    /**
336
     * IS_BLANK.
337
     *
338
     * @param mixed $value Value to check
339
     *
340
     * @deprecated 1.23.0 Use the isBlank() method in the Information\Value class instead
341
     * @see Information\Value::isBlank()
342
     *
343
     * @return array|bool
344
     */
345
    public static function isBlank($value = null)
346
    {
347
        return Information\Value::isBlank($value);
348
    }
349
 
350
    /**
351
     * IS_ERR.
352
     *
353
     * @param mixed $value Value to check
354
     *
355
     * @deprecated 1.23.0 Use the isErr() method in the Information\ErrorValue class instead
356
     * @see Information\ErrorValue::isErr()
357
     *
358
     * @return array|bool
359
     */
360
    public static function isErr($value = '')
361
    {
362
        return Information\ErrorValue::isErr($value);
363
    }
364
 
365
    /**
366
     * IS_ERROR.
367
     *
368
     * @param mixed $value Value to check
369
     *
370
     * @deprecated 1.23.0 Use the isError() method in the Information\ErrorValue class instead
371
     * @see Information\ErrorValue::isError()
372
     *
373
     * @return array|bool
374
     */
375
    public static function isError($value = '')
376
    {
377
        return Information\ErrorValue::isError($value);
378
    }
379
 
380
    /**
381
     * IS_NA.
382
     *
383
     * @param mixed $value Value to check
384
     *
385
     * @deprecated 1.23.0 Use the isNa() method in the Information\ErrorValue class instead
386
     * @see Information\ErrorValue::isNa()
387
     *
388
     * @return array|bool
389
     */
390
    public static function isNa($value = '')
391
    {
392
        return Information\ErrorValue::isNa($value);
393
    }
394
 
395
    /**
396
     * IS_EVEN.
397
     *
398
     * @param mixed $value Value to check
399
     *
400
     * @deprecated 1.23.0 Use the isEven() method in the Information\Value class instead
401
     * @see Information\Value::isEven()
402
     *
403
     * @return array|bool|string
404
     */
405
    public static function isEven($value = null)
406
    {
407
        return Information\Value::isEven($value);
408
    }
409
 
410
    /**
411
     * IS_ODD.
412
     *
413
     * @param mixed $value Value to check
414
     *
415
     * @deprecated 1.23.0 Use the isOdd() method in the Information\Value class instead
416
     * @see Information\Value::isOdd()
417
     *
418
     * @return array|bool|string
419
     */
420
    public static function isOdd($value = null)
421
    {
422
        return Information\Value::isOdd($value);
423
    }
424
 
425
    /**
426
     * IS_NUMBER.
427
     *
428
     * @param mixed $value Value to check
429
     *
430
     * @deprecated 1.23.0 Use the isNumber() method in the Information\Value class instead
431
     * @see Information\Value::isNumber()
432
     *
433
     * @return array|bool
434
     */
435
    public static function isNumber($value = null)
436
    {
437
        return Information\Value::isNumber($value);
438
    }
439
 
440
    /**
441
     * IS_LOGICAL.
442
     *
443
     * @param mixed $value Value to check
444
     *
445
     * @deprecated 1.23.0 Use the isLogical() method in the Information\Value class instead
446
     * @see Information\Value::isLogical()
447
     *
448
     * @return array|bool
449
     */
450
    public static function isLogical($value = null)
451
    {
452
        return Information\Value::isLogical($value);
453
    }
454
 
455
    /**
456
     * IS_TEXT.
457
     *
458
     * @param mixed $value Value to check
459
     *
460
     * @deprecated 1.23.0 Use the isText() method in the Information\Value class instead
461
     * @see Information\Value::isText()
462
     *
463
     * @return array|bool
464
     */
465
    public static function isText($value = null)
466
    {
467
        return Information\Value::isText($value);
468
    }
469
 
470
    /**
471
     * IS_NONTEXT.
472
     *
473
     * @param mixed $value Value to check
474
     *
475
     * @deprecated 1.23.0 Use the isNonText() method in the Information\Value class instead
476
     * @see Information\Value::isNonText()
477
     *
478
     * @return array|bool
479
     */
480
    public static function isNonText($value = null)
481
    {
482
        return Information\Value::isNonText($value);
483
    }
484
 
485
    /**
486
     * N.
487
     *
488
     * Returns a value converted to a number
489
     *
490
     * @deprecated 1.23.0 Use the asNumber() method in the Information\Value class instead
491
     * @see Information\Value::asNumber()
492
     *
493
     * @param null|mixed $value The value you want converted
494
     *
495
     * @return number|string N converts values listed in the following table
496
     *        If value is or refers to N returns
497
     *        A number            That number
498
     *        A date                The serial number of that date
499
     *        TRUE                1
500
     *        FALSE                0
501
     *        An error value        The error value
502
     *        Anything else        0
503
     */
504
    public static function n($value = null)
505
    {
506
        return Information\Value::asNumber($value);
507
    }
508
 
509
    /**
510
     * TYPE.
511
     *
512
     * Returns a number that identifies the type of a value
513
     *
514
     * @deprecated 1.23.0 Use the type() method in the Information\Value class instead
515
     * @see Information\Value::type()
516
     *
517
     * @param null|mixed $value The value you want tested
518
     *
519
     * @return number N converts values listed in the following table
520
     *        If value is or refers to N returns
521
     *        A number            1
522
     *        Text                2
523
     *        Logical Value        4
524
     *        An error value        16
525
     *        Array or Matrix        64
526
     */
527
    public static function TYPE($value = null)
528
    {
529
        return Information\Value::type($value);
530
    }
531
 
532
    /**
533
     * Convert a multi-dimensional array to a simple 1-dimensional array.
534
     *
535
     * @param array|mixed $array Array to be flattened
536
     *
537
     * @return array Flattened array
538
     */
539
    public static function flattenArray($array)
540
    {
541
        if (!is_array($array)) {
542
            return (array) $array;
543
        }
544
 
545
        $flattened = [];
546
        $stack = array_values($array);
547
 
548
        while (!empty($stack)) {
549
            $value = array_shift($stack);
550
 
551
            if (is_array($value)) {
552
                array_unshift($stack, ...array_values($value));
553
            } else {
554
                $flattened[] = $value;
555
            }
556
        }
557
 
558
        return $flattened;
559
    }
560
 
561
    /**
562
     * @param mixed $value
563
     *
564
     * @return null|mixed
565
     */
566
    public static function scalar($value)
567
    {
568
        if (!is_array($value)) {
569
            return $value;
570
        }
571
 
572
        do {
573
            $value = array_pop($value);
574
        } while (is_array($value));
575
 
576
        return $value;
577
    }
578
 
579
    /**
580
     * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing.
581
     *
582
     * @param array|mixed $array Array to be flattened
583
     *
584
     * @return array Flattened array
585
     */
586
    public static function flattenArrayIndexed($array)
587
    {
588
        if (!is_array($array)) {
589
            return (array) $array;
590
        }
591
 
592
        $arrayValues = [];
593
        foreach ($array as $k1 => $value) {
594
            if (is_array($value)) {
595
                foreach ($value as $k2 => $val) {
596
                    if (is_array($val)) {
597
                        foreach ($val as $k3 => $v) {
598
                            $arrayValues[$k1 . '.' . $k2 . '.' . $k3] = $v;
599
                        }
600
                    } else {
601
                        $arrayValues[$k1 . '.' . $k2] = $val;
602
                    }
603
                }
604
            } else {
605
                $arrayValues[$k1] = $value;
606
            }
607
        }
608
 
609
        return $arrayValues;
610
    }
611
 
612
    /**
613
     * Convert an array to a single scalar value by extracting the first element.
614
     *
615
     * @param mixed $value Array or scalar value
616
     *
617
     * @return mixed
618
     */
619
    public static function flattenSingleValue($value = '')
620
    {
621
        while (is_array($value)) {
622
            $value = array_shift($value);
623
        }
624
 
625
        return $value;
626
    }
627
 
628
    /**
629
     * ISFORMULA.
630
     *
631
     * @deprecated 1.23.0 Use the isFormula() method in the Information\Value class instead
632
     * @see Information\Value::isFormula()
633
     *
634
     * @param mixed $cellReference The cell to check
635
     * @param ?Cell $cell The current cell (containing this formula)
636
     *
637
     * @return array|bool|string
638
     */
639
    public static function isFormula($cellReference = '', ?Cell $cell = null)
640
    {
641
        return Information\Value::isFormula($cellReference, $cell);
642
    }
643
 
644
    public static function expandDefinedName(string $coordinate, Cell $cell): string
645
    {
646
        $worksheet = $cell->getWorksheet();
647
        $spreadsheet = $worksheet->getParentOrThrow();
648
        // Uppercase coordinate
649
        $pCoordinatex = strtoupper($coordinate);
650
        // Eliminate leading equal sign
651
        $pCoordinatex = (string) preg_replace('/^=/', '', $pCoordinatex);
652
        $defined = $spreadsheet->getDefinedName($pCoordinatex, $worksheet);
653
        if ($defined !== null) {
654
            $worksheet2 = $defined->getWorkSheet();
655
            if (!$defined->isFormula() && $worksheet2 !== null) {
656
                $coordinate = "'" . $worksheet2->getTitle() . "'!" .
657
                    (string) preg_replace('/^=/', '', str_replace('$', '', $defined->getValue()));
658
            }
659
        }
660
 
661
        return $coordinate;
662
    }
663
 
664
    public static function trimTrailingRange(string $coordinate): string
665
    {
666
        return (string) preg_replace('/:[\\w\$]+$/', '', $coordinate);
667
    }
668
 
669
    public static function trimSheetFromCellReference(string $coordinate): string
670
    {
671
        if (strpos($coordinate, '!') !== false) {
672
            $coordinate = substr($coordinate, strrpos($coordinate, '!') + 1);
673
        }
674
 
675
        return $coordinate;
676
    }
677
}