Completed
Push — master ( 15a86c...ff0242 )
by Michael
03:23
created

MagpieRSS::normalize()   C

Complexity

Conditions 19
Paths 47

Size

Total Lines 50
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 19
eloc 32
c 5
b 0
f 0
nc 47
nop 0
dl 0
loc 50
rs 5.3267

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Project:     MagpieRSS: a simple RSS integration tool
5
 * File:        rss_parse.inc  - parse an RSS or Atom feed
6
 *               return as a simple object.
7
 *
8
 * Handles RSS 0.9x, RSS 2.0, RSS 1.0, and Atom 0.3
9
 *
10
 * The lastest version of MagpieRSS can be obtained from:
11
 * http://magpierss.sourceforge.net
12
 *
13
 * For questions, help, comments, discussion, etc., please join the
14
 * Magpie mailing list:
15
 * [email protected]
16
 *
17
 * @author           Kellan Elliott-McCrea <[email protected]>
18
* @version          0.7a
19
 * @license          GPL
20
 *
21
 */
22
23
define('MAGPIE_DEBUG', 0);
24
25
define('RSS', 'RSS');
26
define('ATOM', 'Atom');
27
28
/**
29
 * Hybrid parser, and object, takes RSS as a string and returns a simple object.
30
 *
31
 * see: rss_fetch.inc for a simpler interface with integrated caching support
32
 *
33
 */
34
class MagpieRSS
35
{
36
    public $parser;
37
38
    public $current_item = array();  // item currently being parsed
39
    public $items        = array();  // collection of parsed items
40
    public $channel      = array();  // hash of channel fields
41
    public $textinput    = array();
42
    public $image        = array();
43
    public $feed_type;
44
    public $feed_version;
45
    public $encoding     = '';       // output encoding of parsed rss
46
47
    public $_source_encoding = '';     // only set if we have to parse xml prolog
48
49
    public $ERROR   = '';
50
    public $WARNING = '';
51
52
    // define some constants
53
54
    public $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
55
    public $_KNOWN_ENCODINGS    = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
56
57
    // parser variables, useless if you're not a parser, treat as private
58
    public $stack             = array(); // parser stack
59
    public $inchannel         = false;
60
    public $initem            = false;
61
    public $incontent         = false; // if in Atom <content mode="xml"> field
62
    public $intextinput       = false;
63
    public $inimage           = false;
64
    public $current_field     = '';
65
    public $current_namespace = false;
66
67
    /**
68
     *  Set up XML parser, parse source, and return populated RSS object..
69
     *
70
     * @param string $source          string containing the RSS to be parsed
71
     *
72
     *  NOTE:  Probably a good idea to leave the encoding options alone unless
73
     *         you know what you're doing as PHP's character set support is
74
     *         a little weird.
75
     *
76
     *  NOTE:  A lot of this is unnecessary but harmless with PHP5
77
     *
78
     *
79
     * @param string $output_encoding output the parsed RSS in this character
80
     *                                set defaults to ISO-8859-1 as this is PHP's
81
     *                                default.
82
     *
83
     *                                  NOTE: might be changed to UTF-8 in future
84
     *                                  versions.
85
     *
86
     * @param string $input_encoding  the character set of the incoming RSS source.
87
     *                                Leave blank and Magpie will try to figure it
88
     *                                out.
89
     *
90
     *
91
     * @param bool   $detect_encoding if false Magpie won't attempt to detect
92
     *                                source encoding. (caveat emptor)
93
     *
94
     */
95
    public function __construct(
96
        $source,
97
        $output_encoding = 'ISO-8859-1',
98
        $input_encoding = null,
99
        $detect_encoding = true
100
    ) {
101
        # if PHP xml isn't compiled in, die
102
        #
103
        if (!function_exists('xml_parser_create')) {
104
            $this->error("Failed to load PHP's XML Extension. " . 'http://www.php.net/manual/en/ref.xml.php',
105
                         E_USER_ERROR);
106
        }
107
108
        list($parser, $source) = $this->create_parser($source, $output_encoding, $input_encoding, $detect_encoding);
109
110
        if (!is_resource($parser)) {
111
            $this->error("Failed to create an instance of PHP's XML parser. "
112
                         . 'http://www.php.net/manual/en/ref.xml.php', E_USER_ERROR);
113
        }
114
115
        $this->parser = $parser;
116
117
        # pass in parser, and a reference to this object
118
        # setup handlers
119
        #
120
        xml_set_object($this->parser, $this);
121
        xml_set_element_handler($this->parser, 'feed_start_element', 'feed_end_element');
122
123
        xml_set_character_data_handler($this->parser, 'feed_cdata');
124
125
        $status = @xml_parse($this->parser, $source);
126
127
        if (!$status) {
128
            $errorcode = xml_get_error_code($this->parser);
129
            if ($errorcode != XML_ERROR_NONE) {
130
                $xml_error  = xml_error_string($errorcode);
131
                $error_line = xml_get_current_line_number($this->parser);
132
                $error_col  = xml_get_current_column_number($this->parser);
133
                $errormsg   = "$xml_error at line $error_line, column $error_col";
134
135
                $this->error($errormsg);
136
            }
137
        }
138
139
        xml_parser_free($this->parser);
140
141
        $this->normalize();
142
    }
143
144
    /**
145
     * @param $p
146
     * @param $element
147
     * @param $attrs
148
     */
149
    public function feed_start_element($p, $element, &$attrs) {
0 ignored issues
show
Unused Code introduced by
The parameter $p is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
150
        $el    = $element = strtolower($element);
151
        $attrs = array_change_key_case($attrs, CASE_LOWER);
152
153
        // check for a namespace, and split if found
154
        $ns = false;
155
        if (strpos($element, ':')) {
156
            list($ns, $el) = explode(':', $element, 2);
157
        }
158
        if ($ns && $ns !== 'rdf') {
159
            $this->current_namespace = $ns;
160
        }
161
162
        # if feed type isn't set, then this is first element of feed
163
        # identify feed from root element
164
        #
165
        if (!isset($this->feed_type)) {
166
            if ($el === 'rdf') {
167
                $this->feed_type    = RSS;
168
                $this->feed_version = '1.0';
169
            } elseif ($el === 'rss') {
170
                $this->feed_type    = RSS;
171
                $this->feed_version = $attrs['version'];
172
            } elseif ($el === 'feed') {
173
                $this->feed_type    = ATOM;
174
                $this->feed_version = $attrs['version'];
175
                $this->inchannel    = true;
176
            }
177
178
            return;
179
        }
180
181
        if ($el === 'channel') {
182
            $this->inchannel = true;
183
        } elseif ($el === 'item' || $el === 'entry') {
184
            $this->initem = true;
185
            if (isset($attrs['rdf:about'])) {
186
                $this->current_item['about'] = $attrs['rdf:about'];
187
            }
188
        }
189
190
        // if we're in the default namespace of an RSS feed,
191
        //  record textinput or image fields
192 View Code Duplication
        elseif ($this->feed_type == RSS && $this->current_namespace === '' && $el === 'textinput') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
193
            $this->intextinput = true;
194
        } elseif ($this->feed_type == RSS && $this->current_namespace === '' && $el === 'image') {
195
            $this->inimage = true;
196
        } # handle atom content constructs
197
        elseif ($this->feed_type == ATOM && in_array($el, $this->_CONTENT_CONSTRUCTS)) {
198
            // avoid clashing w/ RSS mod_content
199
            if ($el === 'content') {
200
                $el = 'atom_content';
201
            }
202
203
            $this->incontent = $el;
204
        } // if inside an Atom content construct (e.g. content or summary) field treat tags as text
205
        elseif ($this->feed_type == ATOM && $this->incontent) {
206
            // if tags are inlined, then flatten
207
            $attrs_str = implode(' ', array_map('map_attrs', array_keys($attrs), array_values($attrs)));
208
209
            $this->append_content("<$element $attrs_str>");
210
211
            array_unshift($this->stack, $el);
212
        }
213
214
        // Atom support many links per containging element.
215
        // Magpie treats link elements of type rel='alternate'
216
        // as being equivalent to RSS's simple link element.
217
        //
218
        elseif ($this->feed_type == ATOM && $el === 'link') {
219
            if (isset($attrs['rel']) && $attrs['rel'] === 'alternate') {
220
                $link_el = 'link';
221
            } else {
222
                $link_el = 'link_' . $attrs['rel'];
223
            }
224
225
            $this->append($link_el, $attrs['href']);
226
        } // set stack[0] to current element
227
        else {
228
            array_unshift($this->stack, $el);
229
        }
230
    }
231
232
    /**
233
     * @param $p
234
     * @param $text
235
     */
236
    public function feed_cdata($p, $text) {
0 ignored issues
show
Unused Code introduced by
The parameter $p is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
237
        if ($this->feed_type == ATOM && $this->incontent) {
238
            $this->append_content($text);
239
        } else {
240
            $current_el = implode('_', array_reverse($this->stack));
241
            $this->append($current_el, $text);
242
        }
243
    }
244
245
    /**
246
     * @param $p
247
     * @param $el
248
     */
249
    public function feed_end_element($p, $el) {
0 ignored issues
show
Unused Code introduced by
The parameter $p is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
250
        $el = strtolower($el);
251
252
        if ($el === 'item' || $el === 'entry') {
253
            $this->items[]      = $this->current_item;
254
            $this->current_item = array();
255
            $this->initem       = false;
256 View Code Duplication
        } elseif ($this->feed_type == RSS && $this->current_namespace === '' && $el === 'textinput') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
257
            $this->intextinput = false;
258
        } elseif ($this->feed_type == RSS && $this->current_namespace === '' && $el === 'image') {
259
            $this->inimage = false;
260
        } elseif ($this->feed_type == ATOM && in_array($el, $this->_CONTENT_CONSTRUCTS)) {
261
            $this->incontent = false;
262
        } elseif ($el === 'channel' || $el === 'feed') {
263
            $this->inchannel = false;
264
        } elseif ($this->feed_type == ATOM && $this->incontent) {
265
            // balance tags properly
266
            // note:  i don't think this is actually neccessary
267
            if ($this->stack[0] == $el) {
268
                $this->append_content("</$el>");
269
            } else {
270
                $this->append_content("<$el />");
271
            }
272
273
            array_shift($this->stack);
274
        } else {
275
            array_shift($this->stack);
276
        }
277
278
        $this->current_namespace = false;
279
    }
280
281
    /**
282
     * @param        $str1
283
     * @param string $str2
284
     */
285
    public function concat(&$str1, $str2 = '') {
286
        if (!isset($str1)) {
287
            $str1 = '';
288
        }
289
        $str1 .= $str2;
290
    }
291
292
    /**
293
     * @param $text
294
     */
295
    public function append_content($text) {
296
        if ($this->initem) {
297
            $this->concat($this->current_item[$this->incontent], $text);
298
        } elseif ($this->inchannel) {
299
            $this->concat($this->channel[$this->incontent], $text);
300
        }
301
    }
302
303
    // smart append - field and namespace aware
304
    /**
305
     * @param $el
306
     * @param $text
307
     */
308
    public function append($el, $text) {
309
        if (!$el) {
310
            return;
311
        }
312
        if ($this->current_namespace) {
313
            if ($this->initem) {
314
                $this->concat($this->current_item[$this->current_namespace][$el], $text);
315
            } elseif ($this->inchannel) {
316
                $this->concat($this->channel[$this->current_namespace][$el], $text);
317
            } elseif ($this->intextinput) {
318
                $this->concat($this->textinput[$this->current_namespace][$el], $text);
319
            } elseif ($this->inimage) {
320
                $this->concat($this->image[$this->current_namespace][$el], $text);
321
            }
322
        } else {
323
            if ($this->initem) {
324
                $this->concat($this->current_item[$el], $text);
325
            } elseif ($this->intextinput) {
326
                $this->concat($this->textinput[$el], $text);
327
            } elseif ($this->inimage) {
328
                $this->concat($this->image[$el], $text);
329
            } elseif ($this->inchannel) {
330
                $this->concat($this->channel[$el], $text);
331
            }
332
        }
333
    }
334
335
    public function normalize() {
336
        // if atom populate rss fields
337
        if ($this->is_atom()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->is_atom() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
338
            $this->channel['description'] = $this->channel['tagline'];
339
            for ($i = 0, $iMax = count($this->items); $i < $iMax; ++$i) {
340
                $item = $this->items[$i];
341
                if (isset($item['summary'])) {
342
                    $item['description'] = $item['summary'];
343
                }
344
                if (isset($item['atom_content'])) {
345
                    $item['content']['encoded'] = $item['atom_content'];
346
                }
347
348
                $atom_date = isset($item['issued']) ? $item['issued'] : @$item['modified'];
349
                if ($atom_date) {
350
                    $epoch = @parse_w3cdtf($atom_date);
351
                    if ($epoch && $epoch > 0) {
352
                        $item['date_timestamp'] = $epoch;
353
                    }
354
                }
355
356
                $this->items[$i] = $item;
357
            }
358
        } elseif ($this->is_rss()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->is_rss() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
359
            $this->channel['tagline'] = $this->channel['description'];
360
            for ($i = 0, $iMax = count($this->items); $i < $iMax; ++$i) {
361
                $item = $this->items[$i];
362
                if (isset($item['description'])) {
363
                    $item['summary'] = $item['description'];
364
                }
365
                if (isset($item['content']['encoded'])) {
366
                    $item['atom_content'] = $item['content']['encoded'];
367
                }
368
369
                if ($this->is_rss() === '1.0' && isset($item['dc']['date'])) {
370
                    $epoch = @parse_w3cdtf($item['dc']['date']);
371
                    if ($epoch && $epoch > 0) {
372
                        $item['date_timestamp'] = $epoch;
373
                    }
374
                } elseif (isset($item['pubdate'])) {
375
                    $epoch = @strtotime($item['pubdate']);
376
                    if ($epoch > 0) {
377
                        $item['date_timestamp'] = $epoch;
378
                    }
379
                }
380
381
                $this->items[$i] = $item;
382
            }
383
        }
384
    }
385
386
    /**
387
     * @return bool
388
     */
389
    public function is_rss() {
390
        if ($this->feed_type == RSS) {
391
            return $this->feed_version;
392
        } else {
393
            return false;
394
        }
395
    }
396
397
    /**
398
     * @return bool
399
     */
400
    public function is_atom() {
401
        if ($this->feed_type == ATOM) {
402
            return $this->feed_version;
403
        } else {
404
            return false;
405
        }
406
    }
407
408
    /**
409
     * return XML parser, and possibly re-encoded source
410
     * @param $source
411
     * @param $out_enc
412
     * @param $in_enc
413
     * @param $detect
414
     * @return array
415
     */
416
    public function create_parser($source, $out_enc, $in_enc, $detect) {
417
        if (substr(phpversion(), 0, 1) == 5) {
418
            $parser = $this->php5_create_parser($in_enc, $detect);
419
        } else {
420
            list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect);
421
        }
422
        if ($out_enc) {
423
            $this->encoding = $out_enc;
424
            xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
425
        }
426
427
        return array($parser, $source);
428
    }
429
430
    /**
431
     * Instantiate an XML parser under PHP5
432
     *
433
     * PHP5 will do a fine job of detecting input encoding
434
     * if passed an empty string as the encoding.
435
     *
436
     * All hail libxml2!
437
     * @param $in_enc
438
     * @param $detect
439
     * @return resource
440
     */
441
    public function php5_create_parser($in_enc, $detect) {
442
        // by default php5 does a fine job of detecting input encodings
443
        if (!$detect && $in_enc) {
444
            return xml_parser_create($in_enc);
445
        } else {
446
            return xml_parser_create('');
447
        }
448
    }
449
450
    /**
451
     * Instaniate an XML parser under PHP4
452
     *
453
     * Unfortunately PHP4's support for character encodings
454
     * and especially XML and character encodings sucks.  As
455
     * long as the documents you parse only contain characters
456
     * from the ISO-8859-1 character set (a superset of ASCII,
457
     * and a subset of UTF-8) you're fine.  However once you
458
     * step out of that comfy little world things get mad, bad,
459
     * and dangerous to know.
460
     *
461
     * The following code is based on SJM's work with FoF
462
     * @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
463
     * @param $source
464
     * @param $in_enc
465
     * @param $detect
466
     * @return array
467
     */
468
    public function php4_create_parser($source, $in_enc, $detect) {
469
        if (!$detect) {
470
            return array(xml_parser_create($in_enc), $source);
471
        }
472
473
        if (!$in_enc) {
474
            if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
475
                $in_enc                = strtoupper($m[1]);
476
                $this->source_encoding = $in_enc;
0 ignored issues
show
Bug introduced by
The property source_encoding does not seem to exist. Did you mean encoding?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
477
            } else {
478
                $in_enc = 'UTF-8';
479
            }
480
        }
481
482
        if ($this->known_encoding($in_enc)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->known_encoding($in_enc) of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
483
            return array(xml_parser_create($in_enc), $source);
484
        }
485
486
        /*
487
        // the dectected encoding is not one of the simple encodings PHP knows
488
489
        // attempt to use the iconv extension to
490
        // cast the XML to a known encoding
491
        // @see http://php.net/iconv
492
493
        if (function_exists('iconv')) {
494
            $encoded_source = iconv($in_enc,'UTF-8', $source);
495
            if ($encoded_source) {
496
                return array(xml_parser_create('UTF-8'), $encoded_source);
497
            }
498
        }
499
500
        // iconv didn't work, try mb_convert_encoding
501
        // @see http://php.net/mbstring
502
        if (function_exists('mb_convert_encoding')) {
503
            $encoded_source = iconv($source, 'UTF-8', $in_enc );
504
            if ($encoded_source) {
505
                return array(xml_parser_create('UTF-8'), $encoded_source);
506
            }
507
        }
508
509
        // else
510
        $this->error("Feed is in an unsupported character encoding. ($in_enc) " .
511
                     "You may see strange artifacts, and mangled characters.",
512
                     E_USER_NOTICE);
513
        */
514
515
        return array(xml_parser_create(), $source);
516
    }
517
518
    /**
519
     * @param $enc
520
     * @return bool|string
521
     */
522
    public function known_encoding($enc) {
523
        $enc = strtoupper($enc);
524
        if (in_array($enc, $this->_KNOWN_ENCODINGS)) {
525
            return $enc;
526
        } else {
527
            return false;
528
        }
529
    }
530
531
    /**
532
     * @param     $errormsg
533
     * @param int $lvl
534
     */
535
    public function error($errormsg, $lvl = E_USER_WARNING) {
536
        // append PHP's error message if track_errors enabled
537
        if (!empty($php_errormsg)) {
538
            $errormsg .= " ($php_errormsg)";
539
        }
540
        if (MAGPIE_DEBUG) {
541
            trigger_error($errormsg, $lvl);
542
        } else {
543
            error_log($errormsg, 0);
544
        }
545
546
        $notices = E_USER_NOTICE | E_NOTICE;
547
        if ($lvl & $notices) {
548
            $this->WARNING = $errormsg;
549
        } else {
550
            $this->ERROR = $errormsg;
551
        }
552
    }
553
} // end class RSS
554
555
/**
556
 * @param $k
557
 * @param $v
558
 * @return string
559
 */
560
function map_attrs($k, $v) {
561
    return "$k=\"$v\"";
562
}
563
564
/**
565
 * @param $date_str
566
 * @return int
567
 */
568
function parse_w3cdtf($date_str) {
569
    # regex to match wc3dtf
570
    $pat = "/(\d{4})-(\d{2})-(\d{2})[T]?(\d{2})?[:]?(\d{2})?(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/";
571
572
    if (preg_match($pat, $date_str, $match)) {
573
        list($year, $month, $day, $hours, $minutes, $seconds) = array(
574
            $match[1],
575
            $match[2],
576
            $match[3],
577
            $match[4],
578
            $match[5],
579
            $match[6]
580
        );
581
582
        # calc epoch for current date assuming GMT
583
        $epoch = gmmktime((int)$hours, (int)$minutes, (int)$seconds, (int)$month, (int)$day, (int)$year);
584
585
        $offset = 0;
586
        if ($match[10] === 'Z') {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
587
            # zulu time, aka GMT
588
        } else {
589
            list($tz_mod, $tz_hour, $tz_min) = array($match[8], $match[9], $match[10]);
590
591
            # zero out the variables
592
            if (!$tz_hour) {
593
                $tz_hour = 0;
594
            }
595
            if (!$tz_min) {
596
                $tz_min = 0;
597
            }
598
599
            $offset_secs = (($tz_hour * 60) + $tz_min) * 60;
600
601
            # is timezone ahead of GMT?  then subtract offset
602
            #
603
            if ($tz_mod == '+') {
604
                $offset_secs = $offset_secs * -1;
605
            }
606
607
            $offset = $offset_secs;
608
        }
609
        $epoch = $epoch + $offset;
610
611
        return $epoch;
612
    } else {
613
        return -1;
614
    }
615
}
616