Issues (3)

source/PurePhpXmlWriter.php (1 issue)

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);
208
        }
209
        catch (\Exception $e){
210
            die('File cannot be opened: ' . $e->getMessage());
0 ignored issues
show
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)
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
}