PurePhpXmlWriter::writeHeader()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 2
rs 10
1
<?php
2
/**
3
 * Main file
4
 *
5
 * All functions for XML writing
6
 *
7
 * @category Controller
8
 * @package PurePhpXmlWriter
9
 * @author Jan Drda <[email protected]>
10
 * @copyright Jan Drda
11
 * @license https://opensource.org/licenses/MIT MIT
12
 *
13
 */
14
15
namespace PurePhpXmlWriter;
16
17
18
class PurePhpXmlWriter
19
{
20
21
    /**
22
     * XML file pointer
23
     *
24
     * @var resource
25
     */
26
    private $_filePointer;
27
28
    /**
29
     * XML file name
30
     *
31
     * @var string
32
     */
33
    private $_fileName;
34
35
    /**
36
     * File encoding
37
     *
38
     * @var string
39
     */
40
    private $_encoding;
41
42
    /**
43
     * Prefix of file name (used only with temporary files)
44
     *
45
     * @var string
46
     */
47
    private $_fileNamePrefix;
48
49
    /**
50
     * Write mode for file
51
     *
52
     * @var string
53
     * @see https://secure.php.net/manual/en/function.fopen.php
54
     */
55
    private $_writeMode;
56
57
    /**
58
     * Indicator if EOL should be used
59
     *
60
     * @var bool
61
     */
62
    private $_isCompressed;
63
64
    /**
65
     * XML file header
66
     *
67
     * @var string
68
     */
69
    private $_fileHeader;
70
71
    /**
72
     * Indicates how deep child element is
73
     *
74
     * @var int
75
     */
76
    private $_elementDeep = 0;
77
78
    /**
79
     * Setter for file name
80
     *
81
     * @param $filename
82
     */
83
    public function setFileName($filename){
84
        $this->_fileName = $filename;
85
    }
86
87
    /**
88
     * Setter for encoding
89
     *
90
     * @param $encoding
91
     */
92
    public function setEncoding($encoding){
93
       $this->_encoding = $encoding;
94
    }
95
96
    /**
97
     * Setter for file name prefix (for generated names only)
98
     *
99
     * @param $fileNamePrefix
100
     */
101
    public function setFileNamePrefix($fileNamePrefix){
102
        $this->_fileNamePrefix = $fileNamePrefix;
103
    }
104
105
    /**
106
     * Setter for write mode
107
     *
108
     * @param $writeMode
109
     * @see https://secure.php.net/manual/en/function.fopen.php
110
     */
111
    public function setWriteMode($writeMode){
112
        $this->_writeMode = $writeMode;
113
    }
114
115
    /**
116
     * Setter for compressed format (EOL used or not)
117
     *
118
     * @param $compressed bool
119
     */
120
    public function setIsCompressed($isCompressed){
121
        $this->_isCompressed = $isCompressed;
122
    }
123
124
125
    /**
126
     * Set file header
127
     *
128
     * @param string $fileHeader
129
     */
130
    public function setHeader($fileHeader = null){
131
132
        /**
133
         * Set standard XML header if not defined
134
         */
135
        if($fileHeader === null){
136
            $this->_fileHeader = '<?xml version="1.0" encoding="' . $this->_encoding .'"?>';
137
        }
138
        else{
139
            $this->_fileHeader = $fileHeader;
140
        }
141
    }
142
143
    /**
144
     * Getter for file name
145
     *
146
     * @return string
147
     */
148
    public function getFileName(){
149
        return $this->_fileName;
150
    }
151
152
    /**
153
     * Constructor
154
     *
155
     * @param string $fileName
156
     * @param bool $autoOpenFile Indicates if file should be opened immediately
157
     * @param string $encoding
158
     * @param string $fileNamePrefix
159
     * @param string $writeMode
160
     * @param bool $compressed Indicates if EOL should be used or not
161
     */
162
    public function __construct($fileName = null, $autoOpenFile = false, $encoding = 'utf-8', $fileNamePrefix = 'ppxw',
163
        $writeMode = 'w', $isCompressed = false)
164
    {
165
        /**
166
         * Setters
167
         */
168
        $this->setEncoding($encoding);
169
        $this->setFileNamePrefix($fileNamePrefix);
170
        $this->setWriteMode($writeMode);
171
        $this->setIsCompressed($isCompressed);
172
        $this->setHeader();
173
174
        /**
175
         * Generate filename if needed
176
         */
177
        if($fileName === null){
178
            $this->setFileName(tempnam(sys_get_temp_dir(), $this->_fileNamePrefix));
179
        }
180
        else{
181
            $this->setFileName($fileName);
182
        }
183
184
        /**
185
         * Autoopen file if needed
186
         */
187
        if($autoOpenFile === true) {
188
            $this->openFile();
189
        }
190
    }
191
192
    /**
193
     * Destructor
194
     *
195
     * Explicitly close the file to make a sure buffer has been written
196
     */
197
    public function __destruct()
198
    {
199
        $this->closeFile();
200
    }
201
202
    /**
203
     * Open XML file
204
     */
205
    public function openFile($autoAddHeader = true){
206
        try {
207
            $this->_filePointer = fopen($this->_fileName, $this->_writeMode);
0 ignored issues
show
Documentation Bug introduced by
It seems like fopen($this->_fileName, $this->_writeMode) can also be of type false. However, the property $_filePointer is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
208
        }
209
        catch (\Exception $e){
210
            die('File cannot be opened: ' . $e->getMessage());
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
211
        }
212
213
        if($autoAddHeader === true){
214
            $this->writeHeader();
215
        }
216
    }
217
218
    /**
219
     * Close XML file if is opened
220
     */
221
    public function closeFile(){
222
        if(is_resource($this->_filePointer) === true){
223
            fclose($this->_filePointer);
224
        }
225
    }
226
227
    /**
228
     * Write the EOL if file is not compressed
229
     */
230
    private function _writeEol(){
231
        if($this->_isCompressed === false){
232
            fwrite($this->_filePointer, PHP_EOL);
233
        }
234
    }
235
236
    /**
237
     * Write the Tabs if file is not compressed
238
     */
239
    private function _writeTabs(){
240
        if($this->_isCompressed === false){
241
            for($a = 0; $a < $this->_elementDeep; $a++) {
242
                fwrite($this->_filePointer, "\t");
243
            }
244
        }
245
    }
246
247
    /**
248
     * Write string to file
249
     *
250
     * @param string $string
251
     * @param bool $useTabs Indicates if use tabs
252
     * @param bool $useEol Indicates if use EOL
253
     */
254
    private function _writeString($string = '', $useTabs = true, $useEol = true){
255
        if($useTabs === true){
256
            $this->_writeTabs();
257
        }
258
259
        fwrite($this->_filePointer, $string);
260
261
        if($useEol === true){
262
            $this->_writeEol();
263
        }
264
    }
265
266
	/**
267
	 * Determines if an array is associative.
268
	 * @param  array  $array
269
	 * @return bool
270
	 */
271
	function isAssoc(array $array)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
272
	{
273
		$keys = array_keys($array);
274
275
		return array_keys($keys) !== $keys;
276
	}
277
278
	/**
279
	 * Concatenates the attribute - value pairs into a string
280
	 *
281
	 * @param array $attr
282
	 */
283
    private function _getAttributes ($attr = null)
284
    {
285
	      $str = '';
286
287
	      if(!is_null($attr) && is_array($attr)) {
288
	      	  // check if is an associative array
289
		        if($this->isAssoc($attr)) {
290
			      	  foreach ($attr as $name => $value) {
291
					          $str .= ' ' . $name . '="' . str_replace('"', "'", $value) . '"';
292
				        }
293
		        }
294
	      }
295
296
	      return $str;
297
    }
298
299
    /**
300
     * Write file header
301
     */
302
    public function writeHeader(){
303
        $this->_writeString($this->_fileHeader, false, true);
304
    }
305
306
    /**
307
     * Open XML element
308
     *
309
     * @param $tag
310
     * @param bool $expectedChildren Indicates if children are expected
311
     * @param array $attr associative array with attribute - value pairs
312
     */
313
    public function openXMLElement($tag, $expectedChildren = true, $attr = null)
314
    {
315
        $this->_writeString('<' . $tag . $this->_getAttributes($attr) . '>', true, $expectedChildren);
316
        $this->_elementDeep++;
317
    }
318
319
    /**
320
     * Close XML element
321
     *
322
     * @param $tag
323
     * @param bool $expectedChildren Indicates if children are expected
324
     */
325
    public function closeXMLElement($tag, $expectedChildren = true)
326
    {
327
        $this->_elementDeep--;
328
        $this->_writeString('</' . $tag . '>', $expectedChildren,true);
329
    }
330
331
    /**
332
     * Write blank XML element
333
     *
334
     * @param $tag
335
     * @param array $attr associative array with attribute - value pairs
336
     */
337
    public function blankXMLElement($tag, $attr = null)
338
    {
339
        $this->_writeString('<' . $tag . $this->_getAttributes($attr) . '/>', true,true);
340
341
    }
342
343
    /**
344
     * Save element with value
345
     *
346
     * @param $tag
347
     * @param $value
348
     * @param int $decimals Only using with number
349
     * @param bool $useCdata
350
     * @param bool $forceCdata
351
     */
352
    public function saveElementWithValue($tag, $value, $decimals = 0, $useCdata = true, $forceCdata = false){
353
354
        /**
355
         * Empty element
356
         */
357
        if (is_numeric($value) === false && strlen(trim($value)) < 1) {
358
            $this->blankXMLElement($tag);
359
        }
360
        else {
361
362
            /**
363
             * Non-empty element
364
             */
365
            if ($useCdata === true && (is_numeric($value) === false || $forceCdata === true)) {
366
                $completeValue = '<![CDATA[' . $value . ']]>';
367
            } else {
368
                if (is_numeric($value) === true) {
369
                    $completeValue = round($value, $decimals);
370
                } else {
371
                    $completeValue = $value;
372
                }
373
            }
374
375
            $this->openXMLElement($tag, false);
376
            $this->_writeString($completeValue, false, false);
377
            $this->closeXMLElement($tag, false);
378
        }
379
    }
380
381
}