1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace OneSheet; |
4
|
|
|
|
5
|
|
|
use OneSheet\Xml\CellXml; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Class CellBuilder to build xml cell strings. |
9
|
|
|
* Wheter a numeric value is written as a number or string type cell |
10
|
|
|
* is simply determined by type, to allow for some control by typecasting. |
11
|
|
|
* |
12
|
|
|
* @package OneSheet |
13
|
|
|
*/ |
14
|
|
|
class CellBuilder |
15
|
|
|
{ |
16
|
|
|
/** |
17
|
|
|
* Array of control characters that should be escaped. |
18
|
|
|
* |
19
|
|
|
* @var array |
20
|
|
|
*/ |
21
|
|
|
private $controlCharacters = array(); |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Array of escape characters to replace control characters. |
25
|
|
|
* |
26
|
|
|
* @var array |
27
|
|
|
*/ |
28
|
|
|
private $escapeCharacters = array(); |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Regex pattern containing control characters. |
32
|
|
|
* |
33
|
|
|
* @var string |
34
|
|
|
*/ |
35
|
|
|
private $escapeCharacterPattern; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* CellBuilder constructor to create escaping arrays. |
39
|
|
|
*/ |
40
|
17 |
|
public function __construct() |
41
|
|
|
{ |
42
|
17 |
|
foreach (range(chr(0), chr(31)) as $key => $character) { |
43
|
17 |
|
if (!in_array($character, array("\n", "\r", "\t"))) { |
44
|
17 |
|
$this->controlCharacters[] = $character; |
45
|
17 |
|
$this->escapeCharacters[] = sprintf('_x%04s_', strtoupper(dechex($key))); |
46
|
17 |
|
} |
47
|
17 |
|
} |
48
|
|
|
|
49
|
17 |
|
$this->escapeCharacterPattern = '~[' . preg_quote(implode($this->controlCharacters)) . ']~'; |
50
|
17 |
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Build and return the string for a single cell. |
54
|
|
|
* |
55
|
|
|
* @param int $rowNumber |
56
|
|
|
* @param int $cellNumber |
57
|
|
|
* @param mixed $cellValue |
58
|
|
|
* @param int $styleId |
59
|
|
|
* |
60
|
|
|
* @return string |
61
|
|
|
*/ |
62
|
6 |
|
public function build($rowNumber, $cellNumber, $cellValue, $styleId = 0) |
63
|
|
|
{ |
64
|
6 |
|
$cellId = $this->getCellId($cellNumber, $rowNumber); |
65
|
|
|
|
66
|
6 |
|
if (is_int($cellValue) || is_float($cellValue)) { |
67
|
3 |
|
return sprintf(CellXml::NUMBER_XML, $cellId, $styleId, $cellValue); |
68
|
4 |
|
} elseif (is_bool($cellValue)) { |
69
|
1 |
|
return sprintf(CellXml::BOOLEAN_XML, $cellId, $styleId, (int)$cellValue); |
70
|
4 |
|
} elseif (0 === strlen($cellValue) && $styleId > 0) { |
71
|
|
|
return sprintf(CellXml::EMPTY_XML, $cellId, $styleId); |
72
|
|
|
} |
73
|
|
|
|
74
|
4 |
|
return sprintf(CellXml::STRING_XML, $cellId, $styleId, $this->escape($cellValue)); |
|
|
|
|
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Turn a integer cell number + row number into a valid cell identifier |
79
|
|
|
* like e.g. A1, Z1, AA1 etc and return it. |
80
|
|
|
* |
81
|
|
|
* @param int $cellNumber |
82
|
|
|
* @param int|null $rowNumber |
83
|
|
|
* |
84
|
|
|
* @return string |
85
|
|
|
*/ |
86
|
7 |
|
public function getCellId($cellNumber, $rowNumber = null) |
87
|
|
|
{ |
88
|
7 |
|
if ($cellNumber / 26 < 1) { |
89
|
7 |
|
return chr(65 + $cellNumber) . $rowNumber; |
90
|
|
|
} |
91
|
|
|
|
92
|
1 |
|
return $this->getCellId(floor($cellNumber / 26) - 1) . chr(65 + $cellNumber % 26) . $rowNumber; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Escape/replace control characters. |
97
|
|
|
* |
98
|
|
|
* @param string $value |
99
|
|
|
* |
100
|
|
|
* @return string |
101
|
|
|
*/ |
102
|
4 |
|
private function escape($value) |
103
|
|
|
{ |
104
|
4 |
|
if (1 !== preg_match($this->escapeCharacterPattern, $value)) { |
105
|
4 |
|
return htmlspecialchars($value, ENT_QUOTES); |
106
|
|
|
} |
107
|
|
|
|
108
|
1 |
|
return str_replace( |
109
|
1 |
|
$this->controlCharacters, $this->escapeCharacters, htmlspecialchars($value, ENT_QUOTES) |
110
|
1 |
|
); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.