PowerPress Podcasting plugin by Blubrry - Version 7.0

Version Description

  • Released on 6/6/2016
  • Added Google Play Music to subscribe page shortcode embed and sidebar widget.
  • Added Stitcher to subscribe page shortcode embed and sidebar widget.
  • New: Strict Category Podcasting. Select a specific category to each episode for statistics tracking and subscription links.
  • New: Podcast only category feeds. You can now mix blog posts with podcast episodes in your podast categories.
  • New: Blubrry Audio Player. Modern podcast audio player complete with subscribe and share tools. For Blubrry Hosting customers only.
  • Updated the getid3 library to latest version.
  • Embed link enhanced to use provided embed. If an embed is placed into an episode, the embed link below the player will use that embed as well.
  • Fixed bug where post type podcast feed with slug 'podcast' will also get the default podcast feed settings (Thanks steveportigal for bringing to our attention).
  • Fixed bug with WP 4.5 dropping the rss-http content type "text/xml".
  • Added shortcode attribute ids="" so you can specify post IDs for the playlist player to display exclusively. (Thanks John Haspel for the feature suggestion!)
  • RSS import now sets the blog post content from the iTunes summary if no description or content:encoded was found in the feed. (Thanks @synthtony for letting us know about the situation)
  • RSS import function calls to mb_stripos() will fallback to stripos() if the PHP mb (Multibyte String) library not available. (Thanks Glen Donohu for bringing to our attention!)
  • Import to podcast category option added.
  • Added audio ac3 and dts to media detection getid3 library (these are not podcast safe formats though we can detect their meta information).
  • Improved logic for setting the iTunes subtitle and iTunes summary from blog post excerpts and blog post content if no custom iTunes summary and/or subtitle is set.
  • Improved feed logic to minimize SQL queries
  • Feed Maximizer option now applies to category podcast only feeds.
  • Renamed "Appearance" settings to "Website" settings
  • Added "Destination" settings for podcast directories and apps
  • You can now select from pages when setting your Subscribe Page.
  • Changed labels for Podcasting SEO guidance to include word "Podcasting" so not to confuse with "Web SEO".
  • Updated Podcasting SEO guidance to reflect how search works in Google Play Music (Thanks Daniel Lewis for confirming what is indexed!)
  • Changed wording for Podcasting SEO guidance with Author field, replaced "slogans" with "nicknames" so it is more clear that we mean slogans for talent on the show.
  • Removed logic to fallback to the HTML5 player for mobile devices. This was only needed when Flash based players were used.
  • Quicktime Embed option for m4a audio removed due to security concerns with Quicktime.
  • SWF embed support dropped.
  • Embed link now toggles embed box when clicked multiple times.
  • ATTENTION: The 1 pixel out audio player will be removed from PowerPress 7.1.
Download this release

Release Info

Developer amandato
Plugin Icon 128x128 PowerPress Podcasting plugin by Blubrry
Version 7.0
Comparing to
See all releases

Code changes from version 6.3.3 to 7.0

class.powerpress-subscribe-widget.php CHANGED
@@ -93,6 +93,12 @@ body .pp-ssb-widget a.pp-ssb-btn:hover {
93
  .pp-ssb-widget-modern a.pp-ssb-email {
94
  background-color: #337EC9;
95
  }
 
 
 
 
 
 
96
  .pp-ssb-widget-modern a.pp-ssb-android {
97
  background-color: #6AB344;
98
  }
@@ -122,6 +128,13 @@ body .pp-ssb-widget a.pp-ssb-btn:hover {
122
  .pp-ssb-android .pp-ssb-ic {
123
  background-position: -98px -98px;
124
  }
 
 
 
 
 
 
 
125
  .pp-ssb-more .pp-ssb-ic {
126
  background-position: -49px -49px;
127
  }
@@ -231,8 +244,10 @@ body .pp-ssb-widget a.pp-ssb-btn:hover {
231
  $ExtraData = array('subscribe_type'=>'general', 'feed'=>'', 'taxonomy_term_id'=>'', 'cat_id'=>'', 'post_type'=>'');
232
  if( !empty($instance['subscribe_type']) )
233
  $ExtraData['subscribe_type'] = $instance['subscribe_type'];
 
 
234
 
235
- switch( $instance['subscribe_type'] )
236
  {
237
  case 'post_type': {
238
 
@@ -269,14 +284,18 @@ body .pp-ssb-widget a.pp-ssb-btn:hover {
269
  }
270
  }; break;
271
  default: {
272
- // Doesn't matter, we'r using the default podcast channel
273
 
274
  };
275
  }
276
 
277
- $Settings = powerpresssubscribe_get_settings( $ExtraData );
278
  if( empty($Settings) )
279
  return;
 
 
 
 
280
 
281
  echo $args['before_widget'];
282
  if ( ! empty( $instance['title'] ) ) {
93
  .pp-ssb-widget-modern a.pp-ssb-email {
94
  background-color: #337EC9;
95
  }
96
+ .pp-ssb-widget-modern a.pp-ssb-stitcher {
97
+ background-color: #197195;
98
+ }
99
+ .pp-ssb-widget-modern a.pp-ssb-gp {
100
+ background-color: #F15832;
101
+ }
102
  .pp-ssb-widget-modern a.pp-ssb-android {
103
  background-color: #6AB344;
104
  }
128
  .pp-ssb-android .pp-ssb-ic {
129
  background-position: -98px -98px;
130
  }
131
+ .pp-ssb-stitcher .pp-ssb-ic {
132
+ background-position: -147px -98px;
133
+ }
134
+ .pp-ssb-gp .pp-ssb-ic {
135
+ background-position: -196px -98px;
136
+ }
137
+
138
  .pp-ssb-more .pp-ssb-ic {
139
  background-position: -49px -49px;
140
  }
244
  $ExtraData = array('subscribe_type'=>'general', 'feed'=>'', 'taxonomy_term_id'=>'', 'cat_id'=>'', 'post_type'=>'');
245
  if( !empty($instance['subscribe_type']) )
246
  $ExtraData['subscribe_type'] = $instance['subscribe_type'];
247
+ else
248
+ $ExtraData['subscribe_type'] = '';
249
 
250
+ switch( $ExtraData['subscribe_type'] )
251
  {
252
  case 'post_type': {
253
 
284
  }
285
  }; break;
286
  default: {
287
+ // Doesn't matter, we're using the default podcast channel
288
 
289
  };
290
  }
291
 
292
+ $Settings = powerpresssubscribe_get_settings( $ExtraData, false );
293
  if( empty($Settings) )
294
  return;
295
+
296
+ if( empty($instance['title']) )
297
+ $instance['title'] = __( 'Subscribe to Podcast' , 'powerpress');
298
+ $instance['title'] = trim($instance['title']);
299
 
300
  echo $args['before_widget'];
301
  if ( ! empty( $instance['title'] ) ) {
css/admin.css CHANGED
@@ -21,7 +21,7 @@ div.powerpress-error,
21
  /* background-color: #ffebe8; /* red */
22
  }
23
  #powerpress_settings {
24
- background-image:url(//images.blubrry.com/powerpress/blubrry_logo5.png);
25
  background-repeat: no-repeat;
26
  background-position: bottom right;
27
  }
@@ -36,12 +36,22 @@ div.powerpress-error,
36
  #powerpress_settings label {
37
  /* font-size: 110%; */
38
  }
 
 
 
 
 
 
39
  .bpp_input_sm {
40
  width: 120px;
41
  }
42
  .bpp_input_med {
43
  width: 250px;
44
  }
 
 
 
 
45
  .powerpress_color_box {
46
  float: left;
47
  width: 16px;
@@ -379,3 +389,64 @@ padding-bottom: 15px;
379
  border-color: #DFDFDF;
380
  border-color: #B3B3B3;
381
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  /* background-color: #ffebe8; /* red */
22
  }
23
  #powerpress_settings {
24
+ background-image:url(//images.blubrry.com/powerpress/blubrry_logo7.png);
25
  background-repeat: no-repeat;
26
  background-position: bottom right;
27
  }
36
  #powerpress_settings label {
37
  /* font-size: 110%; */
38
  }
39
+ #powerpress_settings td {
40
+ padding-top: 12px;
41
+ }
42
+ #powerpress_settings td p {
43
+ padding-bottom: 10px;
44
+ }
45
  .bpp_input_sm {
46
  width: 120px;
47
  }
48
  .bpp_input_med {
49
  width: 250px;
50
  }
51
+ .bpp-input-normal {
52
+ width: 80%;
53
+ }
54
+
55
  .powerpress_color_box {
56
  float: left;
57
  width: 16px;
389
  border-color: #DFDFDF;
390
  border-color: #B3B3B3;
391
  }
392
+
393
+
394
+ /* sections */
395
+ .pp-section {
396
+ clear: both;
397
+ padding: 0px;
398
+ margin: 0px;
399
+ }
400
+ .pp-section dt {
401
+ font-weight: bold;
402
+ }
403
+
404
+ .pp-expand-section {
405
+ text-decoration: none;
406
+ }
407
+ a.pp-expand-section,
408
+ a.pp-expand-section:hover,
409
+ a.pp-expand-section:focus,
410
+ a.pp-expand-section:visited {
411
+ color: #1976D2;
412
+ }
413
+ .pp-expand-section:before,
414
+ .pp-expand-section-expanded:before {
415
+ background-color: #1976D2;
416
+ border: 1px solid #1976D2;
417
+ border-radius: 3px;
418
+ font-weight: bold;
419
+ color: #ffffff;
420
+ height: 20px;
421
+ width: 20px;
422
+ display: inline-block;
423
+ margin-right: 10px;
424
+ text-align: center;
425
+ font-size: 20px;
426
+ }
427
+ .pp-expand-section:before {
428
+ content: ' \25C4'; /* ◄ */
429
+ content: '+';
430
+ }
431
+ .pp-expand-section-expanded:before {
432
+ content: ' \25BC';
433
+ content: '-';
434
+ }
435
+
436
+ /* buttons */
437
+ .wp-core-ui .button-blubrry {
438
+ background: #1976D2;
439
+ border-color: #1976D2;
440
+ color: #FFFFFF;
441
+ }
442
+ .wp-core-ui .button-blubrry-gray {
443
+ background: #f7f7f7;
444
+ border-color: #ccc;
445
+ color: #555;
446
+ }
447
+ .wp-core-ui .button-blubrry:hover,
448
+ .wp-core-ui .button-blubrry:focus {
449
+ background: #0D87E9;
450
+ border-color: #0D87E9;
451
+ color: #FFFFFF;
452
+ }
css/steps.css CHANGED
@@ -88,12 +88,15 @@
88
  }
89
  #powerpress-steps h3.pp-step-h-completed:before
90
  {
91
- content: '\2713';
 
 
 
 
92
  font-weight: 400;
93
  font-size: 32px;
94
  position: absolute;
95
- left: -25px;
96
- top: -5px;
97
  }
98
 
99
  @media screen and (max-width: 400px) {
88
  }
89
  #powerpress-steps h3.pp-step-h-completed:before
90
  {
91
+ content: url(../images/check.svg); /*'\2713';*/
92
+ color: #54A954;
93
+ width: 24px;
94
+ height: 24px;
95
+ padding-right: 5px;
96
  font-weight: 400;
97
  font-size: 32px;
98
  position: absolute;
99
+ left: -30px;
 
100
  }
101
 
102
  @media screen and (max-width: 400px) {
css/subscribe.css CHANGED
@@ -131,6 +131,15 @@ body .pp-sub-widget a:hover {
131
  .pp-sub-widget-modern a.pp-sub-rss {
132
  background-color: #FF8800;
133
  }
 
 
 
 
 
 
 
 
 
134
  .pp-sub-widget-modern a.pp-sub-android {
135
  background-color: #6AB344;
136
  }
@@ -171,6 +180,12 @@ body .pp-sub-widget a:hover {
171
  .pp-sub-android .pp-sub-ic {
172
  background-position: -98px -98px;
173
  }
 
 
 
 
 
 
174
 
175
  /* Retina-specific stuff here */
176
  @media only screen and (-webkit-min-device-pixel-ratio: 2.0),
131
  .pp-sub-widget-modern a.pp-sub-rss {
132
  background-color: #FF8800;
133
  }
134
+
135
+ .pp-sub-widget-modern a.pp-sub-stitcher {
136
+ background-color: #222222;
137
+ background-color: #3ec6ff; /* stitcher light blue */
138
+ background-color: #197195; /* stitcher dark blue */
139
+ }
140
+ .pp-sub-widget-modern a.pp-sub-gp {
141
+ background-color: #F15832;
142
+ }
143
  .pp-sub-widget-modern a.pp-sub-android {
144
  background-color: #6AB344;
145
  }
180
  .pp-sub-android .pp-sub-ic {
181
  background-position: -98px -98px;
182
  }
183
+ .pp-sub-stitcher .pp-sub-ic {
184
+ background-position: -147px -98px;
185
+ }
186
+ .pp-sub-gp .pp-sub-ic {
187
+ background-position: -196px -98px;
188
+ }
189
 
190
  /* Retina-specific stuff here */
191
  @media only screen and (-webkit-min-device-pixel-ratio: 2.0),
feed-podcast.php CHANGED
@@ -22,25 +22,29 @@
22
  return apply_filters('the_excerpt_rss', $output);
23
  }
24
 
25
- $iTunesOrderNumber = 0;
26
- $FeaturedPodcastID = 0;
27
- $iTunesFeatured = get_option('powerpress_itunes_featured');
28
- $feed_slug = get_query_var('feed');
29
- if( !empty($iTunesFeatured[ $feed_slug ]) )
30
- {
31
- if( get_post_type() == 'post' )
 
32
  {
33
- $FeaturedPodcastID = $iTunesFeatured[ $feed_slug ];
34
- $GLOBALS['powerpress_feed']['itunes_feature'] = true; // So any custom order value is not used when looping through the feeds.
35
- $iTunesOrderNumber = 2; // One reserved for featured episode
 
 
 
36
  }
37
  }
38
 
39
 
40
- header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
41
  $more = 1;
42
 
43
- $GeneralSettings = get_option('powerpress_general');
44
  $FeedActionHook = '';
45
  if( !empty($GeneralSettings['feed_action_hook']) )
46
  $FeedActionHook = '_powerpress';
@@ -69,7 +73,13 @@ echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'."\n";
69
 
70
  $ItemCount = 0;
71
  ?>
72
- <?php while( have_posts()) : the_post(); ?>
 
 
 
 
 
 
73
  <item>
74
  <title><?php the_title_rss() ?></title>
75
  <link><?php the_permalink_rss() ?></link>
@@ -78,22 +88,27 @@ echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'."\n";
78
  <?php
79
  if( empty($GLOBALS['powerpress_feed']['feed_maximizer_on']) ) // If feed maximizer off
80
  {
 
 
81
  ?>
82
  <comments><?php comments_link_feed(); ?></comments>
83
- <dc:creator><?php the_author() ?></dc:creator>
84
- <?php the_category_rss('rss2') ?>
85
- <?php if (get_option('rss_use_excerpt')) : ?>
 
 
 
 
 
86
  <description><?php echo powerpress_format_itunes_value( powerpress_get_the_excerpt_rss(), 'description' ); ?></description>
87
- <?php else : ?>
88
  <description><?php echo powerpress_format_itunes_value( powerpress_get_the_excerpt_rss(), 'description' ); ?></description>
89
- <?php if ( strlen( $post->post_content ) > 0 ) : ?>
90
  <content:encoded><![CDATA[<?php the_content_feed('rss2') ?>]]></content:encoded>
91
- <?php else : ?>
92
  <content:encoded><![CDATA[<?php the_excerpt_rss() ?>]]></content:encoded>
93
- <?php endif; ?>
94
- <?php endif; ?>
95
- <wfw:commentRss><?php echo esc_url( get_post_comments_feed_link(null, 'rss2') ); ?></wfw:commentRss>
96
- <slash:comments><?php echo get_comments_number(); ?></slash:comments>
97
  <?php
98
  }
99
  else // If feed maximizer on
@@ -140,7 +155,10 @@ echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'."\n";
140
  query_posts( array('p'=>$FeaturedPodcastID) );
141
  if( have_posts())
142
  {
143
- the_post();
 
 
 
144
  // Featured podcast epiosde, give it the highest itunes:order value...
145
  ?>
146
  <item>
22
  return apply_filters('the_excerpt_rss', $output);
23
  }
24
 
25
+ $GeneralSettings = get_option('powerpress_general');
26
+ $iTunesOrderNumber = 0;
27
+ $FeaturedPodcastID = 0;
28
+
29
+ if( !empty($GeneralSettings['episode_box_feature_in_itunes']) ) {
30
+ $iTunesFeatured = get_option('powerpress_itunes_featured');
31
+ $feed_slug = get_query_var('feed');
32
+ if( !empty($iTunesFeatured[ $feed_slug ]) )
33
  {
34
+ if( get_post_type() == 'post' )
35
+ {
36
+ $FeaturedPodcastID = $iTunesFeatured[ $feed_slug ];
37
+ $GLOBALS['powerpress_feed']['itunes_feature'] = true; // So any custom order value is not used when looping through the feeds.
38
+ $iTunesOrderNumber = 2; // One reserved for featured episode
39
+ }
40
  }
41
  }
42
 
43
 
44
+ header('Content-Type: application/rss+xml; charset=' . get_option('blog_charset'), true);
45
  $more = 1;
46
 
47
+
48
  $FeedActionHook = '';
49
  if( !empty($GeneralSettings['feed_action_hook']) )
50
  $FeedActionHook = '_powerpress';
73
 
74
  $ItemCount = 0;
75
  ?>
76
+ <?php while( have_posts()) :
77
+
78
+ if( empty($GeneralSettings['feed_accel']) )
79
+ the_post();
80
+ else
81
+ $GLOBALS['post'] = $GLOBALS['wp_query']->next_post(); // Use this rather than the_post() that way we do not add additional queries to the database
82
+ ?>
83
  <item>
84
  <title><?php the_title_rss() ?></title>
85
  <link><?php the_permalink_rss() ?></link>
88
  <?php
89
  if( empty($GLOBALS['powerpress_feed']['feed_maximizer_on']) ) // If feed maximizer off
90
  {
91
+
92
+ if( empty($GeneralSettings['feed_accel']) ) {
93
  ?>
94
  <comments><?php comments_link_feed(); ?></comments>
95
+ <wfw:commentRss><?php echo esc_url( get_post_comments_feed_link(null, 'rss2') ); ?></wfw:commentRss>
96
+ <slash:comments><?php echo get_comments_number(); ?></slash:comments>
97
+ <?php } // end powerpress feed comments
98
+
99
+ if( empty($GeneralSettings['feed_accel']) ) {
100
+ the_category_rss('rss2');
101
+ }
102
+ if (get_option('rss_use_excerpt')) { ?>
103
  <description><?php echo powerpress_format_itunes_value( powerpress_get_the_excerpt_rss(), 'description' ); ?></description>
104
+ <?php } else { // else no rss_use_excerpt ?>
105
  <description><?php echo powerpress_format_itunes_value( powerpress_get_the_excerpt_rss(), 'description' ); ?></description>
106
+ <?php if ( strlen( $post->post_content ) > 0 ) { ?>
107
  <content:encoded><![CDATA[<?php the_content_feed('rss2') ?>]]></content:encoded>
108
+ <?php } else { // else strlen( $post->post_content ) <= 0 ?>
109
  <content:encoded><![CDATA[<?php the_excerpt_rss() ?>]]></content:encoded>
110
+ <?php } // end else strlen( $post->post_content ) <= 0 ?>
111
+ <?php } // end else no rss_use_excerpt ?>
 
 
112
  <?php
113
  }
114
  else // If feed maximizer on
155
  query_posts( array('p'=>$FeaturedPodcastID) );
156
  if( have_posts())
157
  {
158
+ if( empty($GeneralSettings['feed_accel']) )
159
+ the_post();
160
+ else
161
+ $GLOBALS['post'] = $GLOBALS['wp_query']->next_post(); // Use this rather than the_post() that way we do not add additional queries to the database
162
  // Featured podcast epiosde, give it the highest itunes:order value...
163
  ?>
164
  <item>
getid3/getid3.lib.php CHANGED
@@ -1,1376 +1,1405 @@
1
- <?php
2
- /////////////////////////////////////////////////////////////////
3
- /// getID3() by James Heinrich <info@getid3.org> //
4
- // available at http://getid3.sourceforge.net //
5
- // or http://www.getid3.org //
6
- // also https://github.com/JamesHeinrich/getID3 //
7
- /////////////////////////////////////////////////////////////////
8
- // //
9
- // getid3.lib.php - part of getID3() //
10
- // See readme.txt for more details //
11
- // ///
12
- /////////////////////////////////////////////////////////////////
13
-
14
-
15
- class getid3_lib
16
- {
17
-
18
- public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
19
- $returnstring = '';
20
- for ($i = 0; $i < strlen($string); $i++) {
21
- if ($hex) {
22
- $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
23
- } else {
24
- $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤');
25
- }
26
- if ($spaces) {
27
- $returnstring .= ' ';
28
- }
29
- }
30
- if (!empty($htmlencoding)) {
31
- if ($htmlencoding === true) {
32
- $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean
33
- }
34
- $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
35
- }
36
- return $returnstring;
37
- }
38
-
39
- public static function trunc($floatnumber) {
40
- // truncates a floating-point number at the decimal point
41
- // returns int (if possible, otherwise float)
42
- if ($floatnumber >= 1) {
43
- $truncatednumber = floor($floatnumber);
44
- } elseif ($floatnumber <= -1) {
45
- $truncatednumber = ceil($floatnumber);
46
- } else {
47
- $truncatednumber = 0;
48
- }
49
- if (self::intValueSupported($truncatednumber)) {
50
- $truncatednumber = (int) $truncatednumber;
51
- }
52
- return $truncatednumber;
53
- }
54
-
55
-
56
- public static function safe_inc(&$variable, $increment=1) {
57
- if (isset($variable)) {
58
- $variable += $increment;
59
- } else {
60
- $variable = $increment;
61
- }
62
- return true;
63
- }
64
-
65
- public static function CastAsInt($floatnum) {
66
- // convert to float if not already
67
- $floatnum = (float) $floatnum;
68
-
69
- // convert a float to type int, only if possible
70
- if (self::trunc($floatnum) == $floatnum) {
71
- // it's not floating point
72
- if (self::intValueSupported($floatnum)) {
73
- // it's within int range
74
- $floatnum = (int) $floatnum;
75
- }
76
- }
77
- return $floatnum;
78
- }
79
-
80
- public static function intValueSupported($num) {
81
- // check if integers are 64-bit
82
- static $hasINT64 = null;
83
- if ($hasINT64 === null) { // 10x faster than is_null()
84
- $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
85
- if (!$hasINT64 && !defined('PHP_INT_MIN')) {
86
- define('PHP_INT_MIN', ~PHP_INT_MAX);
87
- }
88
- }
89
- // if integers are 64-bit - no other check required
90
- if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
91
- return true;
92
- }
93
- return false;
94
- }
95
-
96
- public static function DecimalizeFraction($fraction) {
97
- list($numerator, $denominator) = explode('/', $fraction);
98
- return $numerator / ($denominator ? $denominator : 1);
99
- }
100
-
101
-
102
- public static function DecimalBinary2Float($binarynumerator) {
103
- $numerator = self::Bin2Dec($binarynumerator);
104
- $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
105
- return ($numerator / $denominator);
106
- }
107
-
108
-
109
- public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
110
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
111
- if (strpos($binarypointnumber, '.') === false) {
112
- $binarypointnumber = '0.'.$binarypointnumber;
113
- } elseif ($binarypointnumber{0} == '.') {
114
- $binarypointnumber = '0'.$binarypointnumber;
115
- }
116
- $exponent = 0;
117
- while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
118
- if (substr($binarypointnumber, 1, 1) == '.') {
119
- $exponent--;
120
- $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
121
- } else {
122
- $pointpos = strpos($binarypointnumber, '.');
123
- $exponent += ($pointpos - 1);
124
- $binarypointnumber = str_replace('.', '', $binarypointnumber);
125
- $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
126
- }
127
- }
128
- $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
129
- return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
130
- }
131
-
132
-
133
- public static function Float2BinaryDecimal($floatvalue) {
134
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
135
- $maxbits = 128; // to how many bits of precision should the calculations be taken?
136
- $intpart = self::trunc($floatvalue);
137
- $floatpart = abs($floatvalue - $intpart);
138
- $pointbitstring = '';
139
- while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
140
- $floatpart *= 2;
141
- $pointbitstring .= (string) self::trunc($floatpart);
142
- $floatpart -= self::trunc($floatpart);
143
- }
144
- $binarypointnumber = decbin($intpart).'.'.$pointbitstring;
145
- return $binarypointnumber;
146
- }
147
-
148
-
149
- public static function Float2String($floatvalue, $bits) {
150
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
151
- switch ($bits) {
152
- case 32:
153
- $exponentbits = 8;
154
- $fractionbits = 23;
155
- break;
156
-
157
- case 64:
158
- $exponentbits = 11;
159
- $fractionbits = 52;
160
- break;
161
-
162
- default:
163
- return false;
164
- break;
165
- }
166
- if ($floatvalue >= 0) {
167
- $signbit = '0';
168
- } else {
169
- $signbit = '1';
170
- }
171
- $normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits);
172
- $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
173
- $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
174
- $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
175
-
176
- return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
177
- }
178
-
179
-
180
- public static function LittleEndian2Float($byteword) {
181
- return self::BigEndian2Float(strrev($byteword));
182
- }
183
-
184
-
185
- public static function BigEndian2Float($byteword) {
186
- // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
187
- // http://www.psc.edu/general/software/packages/ieee/ieee.html
188
- // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
189
-
190
- $bitword = self::BigEndian2Bin($byteword);
191
- if (!$bitword) {
192
- return 0;
193
- }
194
- $signbit = $bitword{0};
195
-
196
- switch (strlen($byteword) * 8) {
197
- case 32:
198
- $exponentbits = 8;
199
- $fractionbits = 23;
200
- break;
201
-
202
- case 64:
203
- $exponentbits = 11;
204
- $fractionbits = 52;
205
- break;
206
-
207
- case 80:
208
- // 80-bit Apple SANE format
209
- // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
210
- $exponentstring = substr($bitword, 1, 15);
211
- $isnormalized = intval($bitword{16});
212
- $fractionstring = substr($bitword, 17, 63);
213
- $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
214
- $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
215
- $floatvalue = $exponent * $fraction;
216
- if ($signbit == '1') {
217
- $floatvalue *= -1;
218
- }
219
- return $floatvalue;
220
- break;
221
-
222
- default:
223
- return false;
224
- break;
225
- }
226
- $exponentstring = substr($bitword, 1, $exponentbits);
227
- $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
228
- $exponent = self::Bin2Dec($exponentstring);
229
- $fraction = self::Bin2Dec($fractionstring);
230
-
231
- if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
232
- // Not a Number
233
- $floatvalue = false;
234
- } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
235
- if ($signbit == '1') {
236
- $floatvalue = '-infinity';
237
- } else {
238
- $floatvalue = '+infinity';
239
- }
240
- } elseif (($exponent == 0) && ($fraction == 0)) {
241
- if ($signbit == '1') {
242
- $floatvalue = -0;
243
- } else {
244
- $floatvalue = 0;
245
- }
246
- $floatvalue = ($signbit ? 0 : -0);
247
- } elseif (($exponent == 0) && ($fraction != 0)) {
248
- // These are 'unnormalized' values
249
- $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring);
250
- if ($signbit == '1') {
251
- $floatvalue *= -1;
252
- }
253
- } elseif ($exponent != 0) {
254
- $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring));
255
- if ($signbit == '1') {
256
- $floatvalue *= -1;
257
- }
258
- }
259
- return (float) $floatvalue;
260
- }
261
-
262
-
263
- public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
264
- $intvalue = 0;
265
- $bytewordlen = strlen($byteword);
266
- if ($bytewordlen == 0) {
267
- return false;
268
- }
269
- for ($i = 0; $i < $bytewordlen; $i++) {
270
- if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
271
- //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
272
- $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
273
- } else {
274
- $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
275
- }
276
- }
277
- if ($signed && !$synchsafe) {
278
- // synchsafe ints are not allowed to be signed
279
- if ($bytewordlen <= PHP_INT_SIZE) {
280
- $signMaskBit = 0x80 << (8 * ($bytewordlen - 1));
281
- if ($intvalue & $signMaskBit) {
282
- $intvalue = 0 - ($intvalue & ($signMaskBit - 1));
283
- }
284
- } else {
285
- throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()');
286
- }
287
- }
288
- return self::CastAsInt($intvalue);
289
- }
290
-
291
-
292
- public static function LittleEndian2Int($byteword, $signed=false) {
293
- return self::BigEndian2Int(strrev($byteword), false, $signed);
294
- }
295
-
296
-
297
- public static function BigEndian2Bin($byteword) {
298
- $binvalue = '';
299
- $bytewordlen = strlen($byteword);
300
- for ($i = 0; $i < $bytewordlen; $i++) {
301
- $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
302
- }
303
- return $binvalue;
304
- }
305
-
306
-
307
- public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
308
- if ($number < 0) {
309
- throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
310
- }
311
- $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
312
- $intstring = '';
313
- if ($signed) {
314
- if ($minbytes > PHP_INT_SIZE) {
315
- throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()');
316
- }
317
- $number = $number & (0x80 << (8 * ($minbytes - 1)));
318
- }
319
- while ($number != 0) {
320
- $quotient = ($number / ($maskbyte + 1));
321
- $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring;
322
- $number = floor($quotient);
323
- }
324
- return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
325
- }
326
-
327
-
328
- public static function Dec2Bin($number) {
329
- while ($number >= 256) {
330
- $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
331
- $number = floor($number / 256);
332
- }
333
- $bytes[] = $number;
334
- $binstring = '';
335
- for ($i = 0; $i < count($bytes); $i++) {
336
- $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
337
- }
338
- return $binstring;
339
- }
340
-
341
-
342
- public static function Bin2Dec($binstring, $signed=false) {
343
- $signmult = 1;
344
- if ($signed) {
345
- if ($binstring{0} == '1') {
346
- $signmult = -1;
347
- }
348
- $binstring = substr($binstring, 1);
349
- }
350
- $decvalue = 0;
351
- for ($i = 0; $i < strlen($binstring); $i++) {
352
- $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
353
- }
354
- return self::CastAsInt($decvalue * $signmult);
355
- }
356
-
357
-
358
- public static function Bin2String($binstring) {
359
- // return 'hi' for input of '0110100001101001'
360
- $string = '';
361
- $binstringreversed = strrev($binstring);
362
- for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
363
- $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
364
- }
365
- return $string;
366
- }
367
-
368
-
369
- public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
370
- $intstring = '';
371
- while ($number > 0) {
372
- if ($synchsafe) {
373
- $intstring = $intstring.chr($number & 127);
374
- $number >>= 7;
375
- } else {
376
- $intstring = $intstring.chr($number & 255);
377
- $number >>= 8;
378
- }
379
- }
380
- return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
381
- }
382
-
383
-
384
- public static function array_merge_clobber($array1, $array2) {
385
- // written by kcØhireability*com
386
- // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
387
- if (!is_array($array1) || !is_array($array2)) {
388
- return false;
389
- }
390
- $newarray = $array1;
391
- foreach ($array2 as $key => $val) {
392
- if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
393
- $newarray[$key] = self::array_merge_clobber($newarray[$key], $val);
394
- } else {
395
- $newarray[$key] = $val;
396
- }
397
- }
398
- return $newarray;
399
- }
400
-
401
-
402
- public static function array_merge_noclobber($array1, $array2) {
403
- if (!is_array($array1) || !is_array($array2)) {
404
- return false;
405
- }
406
- $newarray = $array1;
407
- foreach ($array2 as $key => $val) {
408
- if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
409
- $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val);
410
- } elseif (!isset($newarray[$key])) {
411
- $newarray[$key] = $val;
412
- }
413
- }
414
- return $newarray;
415
- }
416
-
417
-
418
- public static function ksort_recursive(&$theArray) {
419
- ksort($theArray);
420
- foreach ($theArray as $key => $value) {
421
- if (is_array($value)) {
422
- self::ksort_recursive($theArray[$key]);
423
- }
424
- }
425
- return true;
426
- }
427
-
428
- public static function fileextension($filename, $numextensions=1) {
429
- if (strstr($filename, '.')) {
430
- $reversedfilename = strrev($filename);
431
- $offset = 0;
432
- for ($i = 0; $i < $numextensions; $i++) {
433
- $offset = strpos($reversedfilename, '.', $offset + 1);
434
- if ($offset === false) {
435
- return '';
436
- }
437
- }
438
- return strrev(substr($reversedfilename, 0, $offset));
439
- }
440
- return '';
441
- }
442
-
443
-
444
- public static function PlaytimeString($seconds) {
445
- $sign = (($seconds < 0) ? '-' : '');
446
- $seconds = round(abs($seconds));
447
- $H = (int) floor( $seconds / 3600);
448
- $M = (int) floor(($seconds - (3600 * $H) ) / 60);
449
- $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
450
- return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
451
- }
452
-
453
-
454
- public static function DateMac2Unix($macdate) {
455
- // Macintosh timestamp: seconds since 00:00h January 1, 1904
456
- // UNIX timestamp: seconds since 00:00h January 1, 1970
457
- return self::CastAsInt($macdate - 2082844800);
458
- }
459
-
460
-
461
- public static function FixedPoint8_8($rawdata) {
462
- return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
463
- }
464
-
465
-
466
- public static function FixedPoint16_16($rawdata) {
467
- return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
468
- }
469
-
470
-
471
- public static function FixedPoint2_30($rawdata) {
472
- $binarystring = self::BigEndian2Bin($rawdata);
473
- return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
474
- }
475
-
476
-
477
- public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
478
- // assigns $Value to a nested array path:
479
- // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
480
- // is the same as:
481
- // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
482
- // or
483
- // $foo['path']['to']['my'] = 'file.txt';
484
- $ArrayPath = ltrim($ArrayPath, $Separator);
485
- if (($pos = strpos($ArrayPath, $Separator)) !== false) {
486
- $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
487
- } else {
488
- $ReturnedArray[$ArrayPath] = $Value;
489
- }
490
- return $ReturnedArray;
491
- }
492
-
493
- public static function array_max($arraydata, $returnkey=false) {
494
- $maxvalue = false;
495
- $maxkey = false;
496
- foreach ($arraydata as $key => $value) {
497
- if (!is_array($value)) {
498
- if ($value > $maxvalue) {
499
- $maxvalue = $value;
500
- $maxkey = $key;
501
- }
502
- }
503
- }
504
- return ($returnkey ? $maxkey : $maxvalue);
505
- }
506
-
507
- public static function array_min($arraydata, $returnkey=false) {
508
- $minvalue = false;
509
- $minkey = false;
510
- foreach ($arraydata as $key => $value) {
511
- if (!is_array($value)) {
512
- if ($value > $minvalue) {
513
- $minvalue = $value;
514
- $minkey = $key;
515
- }
516
- }
517
- }
518
- return ($returnkey ? $minkey : $minvalue);
519
- }
520
-
521
- public static function XML2array($XMLstring) {
522
- if ( function_exists( 'simplexml_load_string' ) && function_exists( 'libxml_disable_entity_loader' ) ) {
523
- $loader = libxml_disable_entity_loader( true );
524
- $XMLobject = simplexml_load_string( $XMLstring, 'SimpleXMLElement', LIBXML_NOENT );
525
- $return = self::SimpleXMLelement2array( $XMLobject );
526
- libxml_disable_entity_loader( $loader );
527
- return $return;
528
- }
529
- return false;
530
- }
531
-
532
- public static function SimpleXMLelement2array($XMLobject) {
533
- if (!is_object($XMLobject) && !is_array($XMLobject)) {
534
- return $XMLobject;
535
- }
536
- $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
537
- foreach ($XMLarray as $key => $value) {
538
- $XMLarray[$key] = self::SimpleXMLelement2array($value);
539
- }
540
- return $XMLarray;
541
- }
542
-
543
-
544
- // Allan Hansen <ahØartemis*dk>
545
- // self::md5_data() - returns md5sum for a file from startuing position to absolute end position
546
- public static function hash_data($file, $offset, $end, $algorithm) {
547
- static $tempdir = '';
548
- if (!self::intValueSupported($end)) {
549
- return false;
550
- }
551
- switch ($algorithm) {
552
- case 'md5':
553
- $hash_function = 'md5_file';
554
- $unix_call = 'md5sum';
555
- $windows_call = 'md5sum.exe';
556
- $hash_length = 32;
557
- break;
558
-
559
- case 'sha1':
560
- $hash_function = 'sha1_file';
561
- $unix_call = 'sha1sum';
562
- $windows_call = 'sha1sum.exe';
563
- $hash_length = 40;
564
- break;
565
-
566
- default:
567
- throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
568
- break;
569
- }
570
- $size = $end - $offset;
571
- while (true) {
572
- if (GETID3_OS_ISWINDOWS) {
573
-
574
- // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
575
- // Fall back to create-temp-file method:
576
- if ($algorithm == 'sha1') {
577
- break;
578
- }
579
-
580
- $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
581
- foreach ($RequiredFiles as $required_file) {
582
- if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
583
- // helper apps not available - fall back to old method
584
- break 2;
585
- }
586
- }
587
- $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
588
- $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
589
- $commandline .= GETID3_HELPERAPPSDIR.$windows_call;
590
-
591
- } else {
592
-
593
- $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
594
- $commandline .= 'tail -c'.$size.' | ';
595
- $commandline .= $unix_call;
596
-
597
- }
598
- if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
599
- //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
600
- break;
601
- }
602
- return substr(`$commandline`, 0, $hash_length);
603
- }
604
-
605
- if (empty($tempdir)) {
606
- // yes this is ugly, feel free to suggest a better way
607
- require_once(dirname(__FILE__).'/getid3.php');
608
- $getid3_temp = new getID3();
609
- $tempdir = $getid3_temp->tempdir;
610
- unset($getid3_temp);
611
- }
612
- // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
613
- if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
614
- // can't find anywhere to create a temp file, just fail
615
- return false;
616
- }
617
-
618
- // Init
619
- $result = false;
620
-
621
- // copy parts of file
622
- try {
623
- self::CopyFileParts($file, $data_filename, $offset, $end - $offset);
624
- $result = $hash_function($data_filename);
625
- } catch (Exception $e) {
626
- throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
627
- }
628
- unlink($data_filename);
629
- return $result;
630
- }
631
-
632
- public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
633
- if (!self::intValueSupported($offset + $length)) {
634
- throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
635
- }
636
- if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
637
- if (($fp_dest = fopen($filename_dest, 'wb'))) {
638
- if (fseek($fp_src, $offset) == 0) {
639
- $byteslefttowrite = $length;
640
- while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
641
- $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
642
- $byteslefttowrite -= $byteswritten;
643
- }
644
- return true;
645
- } else {
646
- throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
647
- }
648
- fclose($fp_dest);
649
- } else {
650
- throw new Exception('failed to create file for writing '.$filename_dest);
651
- }
652
- fclose($fp_src);
653
- } else {
654
- throw new Exception('failed to open file for reading '.$filename_source);
655
- }
656
- return false;
657
- }
658
-
659
- public static function iconv_fallback_int_utf8($charval) {
660
- if ($charval < 128) {
661
- // 0bbbbbbb
662
- $newcharstring = chr($charval);
663
- } elseif ($charval < 2048) {
664
- // 110bbbbb 10bbbbbb
665
- $newcharstring = chr(($charval >> 6) | 0xC0);
666
- $newcharstring .= chr(($charval & 0x3F) | 0x80);
667
- } elseif ($charval < 65536) {
668
- // 1110bbbb 10bbbbbb 10bbbbbb
669
- $newcharstring = chr(($charval >> 12) | 0xE0);
670
- $newcharstring .= chr(($charval >> 6) | 0xC0);
671
- $newcharstring .= chr(($charval & 0x3F) | 0x80);
672
- } else {
673
- // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
674
- $newcharstring = chr(($charval >> 18) | 0xF0);
675
- $newcharstring .= chr(($charval >> 12) | 0xC0);
676
- $newcharstring .= chr(($charval >> 6) | 0xC0);
677
- $newcharstring .= chr(($charval & 0x3F) | 0x80);
678
- }
679
- return $newcharstring;
680
- }
681
-
682
- // ISO-8859-1 => UTF-8
683
- public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
684
- if (function_exists('utf8_encode')) {
685
- return utf8_encode($string);
686
- }
687
- // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
688
- $newcharstring = '';
689
- if ($bom) {
690
- $newcharstring .= "\xEF\xBB\xBF";
691
- }
692
- for ($i = 0; $i < strlen($string); $i++) {
693
- $charval = ord($string{$i});
694
- $newcharstring .= self::iconv_fallback_int_utf8($charval);
695
- }
696
- return $newcharstring;
697
- }
698
-
699
- // ISO-8859-1 => UTF-16BE
700
- public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
701
- $newcharstring = '';
702
- if ($bom) {
703
- $newcharstring .= "\xFE\xFF";
704
- }
705
- for ($i = 0; $i < strlen($string); $i++) {
706
- $newcharstring .= "\x00".$string{$i};
707
- }
708
- return $newcharstring;
709
- }
710
-
711
- // ISO-8859-1 => UTF-16LE
712
- public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
713
- $newcharstring = '';
714
- if ($bom) {
715
- $newcharstring .= "\xFF\xFE";
716
- }
717
- for ($i = 0; $i < strlen($string); $i++) {
718
- $newcharstring .= $string{$i}."\x00";
719
- }
720
- return $newcharstring;
721
- }
722
-
723
- // ISO-8859-1 => UTF-16LE (BOM)
724
- public static function iconv_fallback_iso88591_utf16($string) {
725
- return self::iconv_fallback_iso88591_utf16le($string, true);
726
- }
727
-
728
- // UTF-8 => ISO-8859-1
729
- public static function iconv_fallback_utf8_iso88591($string) {
730
- if (function_exists('utf8_decode')) {
731
- return utf8_decode($string);
732
- }
733
- // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
734
- $newcharstring = '';
735
- $offset = 0;
736
- $stringlength = strlen($string);
737
- while ($offset < $stringlength) {
738
- if ((ord($string{$offset}) | 0x07) == 0xF7) {
739
- // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
740
- $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
741
- ((ord($string{($offset + 1)}) & 0x3F) << 12) &
742
- ((ord($string{($offset + 2)}) & 0x3F) << 6) &
743
- (ord($string{($offset + 3)}) & 0x3F);
744
- $offset += 4;
745
- } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
746
- // 1110bbbb 10bbbbbb 10bbbbbb
747
- $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
748
- ((ord($string{($offset + 1)}) & 0x3F) << 6) &
749
- (ord($string{($offset + 2)}) & 0x3F);
750
- $offset += 3;
751
- } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
752
- // 110bbbbb 10bbbbbb
753
- $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
754
- (ord($string{($offset + 1)}) & 0x3F);
755
- $offset += 2;
756
- } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
757
- // 0bbbbbbb
758
- $charval = ord($string{$offset});
759
- $offset += 1;
760
- } else {
761
- // error? throw some kind of warning here?
762
- $charval = false;
763
- $offset += 1;
764
- }
765
- if ($charval !== false) {
766
- $newcharstring .= (($charval < 256) ? chr($charval) : '?');
767
- }
768
- }
769
- return $newcharstring;
770
- }
771
-
772
- // UTF-8 => UTF-16BE
773
- public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
774
- $newcharstring = '';
775
- if ($bom) {
776
- $newcharstring .= "\xFE\xFF";
777
- }
778
- $offset = 0;
779
- $stringlength = strlen($string);
780
- while ($offset < $stringlength) {
781
- if ((ord($string{$offset}) | 0x07) == 0xF7) {
782
- // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
783
- $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
784
- ((ord($string{($offset + 1)}) & 0x3F) << 12) &
785
- ((ord($string{($offset + 2)}) & 0x3F) << 6) &
786
- (ord($string{($offset + 3)}) & 0x3F);
787
- $offset += 4;
788
- } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
789
- // 1110bbbb 10bbbbbb 10bbbbbb
790
- $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
791
- ((ord($string{($offset + 1)}) & 0x3F) << 6) &
792
- (ord($string{($offset + 2)}) & 0x3F);
793
- $offset += 3;
794
- } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
795
- // 110bbbbb 10bbbbbb
796
- $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
797
- (ord($string{($offset + 1)}) & 0x3F);
798
- $offset += 2;
799
- } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
800
- // 0bbbbbbb
801
- $charval = ord($string{$offset});
802
- $offset += 1;
803
- } else {
804
- // error? throw some kind of warning here?
805
- $charval = false;
806
- $offset += 1;
807
- }
808
- if ($charval !== false) {
809
- $newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?');
810
- }
811
- }
812
- return $newcharstring;
813
- }
814
-
815
- // UTF-8 => UTF-16LE
816
- public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
817
- $newcharstring = '';
818
- if ($bom) {
819
- $newcharstring .= "\xFF\xFE";
820
- }
821
- $offset = 0;
822
- $stringlength = strlen($string);
823
- while ($offset < $stringlength) {
824
- if ((ord($string{$offset}) | 0x07) == 0xF7) {
825
- // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
826
- $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
827
- ((ord($string{($offset + 1)}) & 0x3F) << 12) &
828
- ((ord($string{($offset + 2)}) & 0x3F) << 6) &
829
- (ord($string{($offset + 3)}) & 0x3F);
830
- $offset += 4;
831
- } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
832
- // 1110bbbb 10bbbbbb 10bbbbbb
833
- $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
834
- ((ord($string{($offset + 1)}) & 0x3F) << 6) &
835
- (ord($string{($offset + 2)}) & 0x3F);
836
- $offset += 3;
837
- } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
838
- // 110bbbbb 10bbbbbb
839
- $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
840
- (ord($string{($offset + 1)}) & 0x3F);
841
- $offset += 2;
842
- } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
843
- // 0bbbbbbb
844
- $charval = ord($string{$offset});
845
- $offset += 1;
846
- } else {
847
- // error? maybe throw some warning here?
848
- $charval = false;
849
- $offset += 1;
850
- }
851
- if ($charval !== false) {
852
- $newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00");
853
- }
854
- }
855
- return $newcharstring;
856
- }
857
-
858
- // UTF-8 => UTF-16LE (BOM)
859
- public static function iconv_fallback_utf8_utf16($string) {
860
- return self::iconv_fallback_utf8_utf16le($string, true);
861
- }
862
-
863
- // UTF-16BE => UTF-8
864
- public static function iconv_fallback_utf16be_utf8($string) {
865
- if (substr($string, 0, 2) == "\xFE\xFF") {
866
- // strip BOM
867
- $string = substr($string, 2);
868
- }
869
- $newcharstring = '';
870
- for ($i = 0; $i < strlen($string); $i += 2) {
871
- $charval = self::BigEndian2Int(substr($string, $i, 2));
872
- $newcharstring .= self::iconv_fallback_int_utf8($charval);
873
- }
874
- return $newcharstring;
875
- }
876
-
877
- // UTF-16LE => UTF-8
878
- public static function iconv_fallback_utf16le_utf8($string) {
879
- if (substr($string, 0, 2) == "\xFF\xFE") {
880
- // strip BOM
881
- $string = substr($string, 2);
882
- }
883
- $newcharstring = '';
884
- for ($i = 0; $i < strlen($string); $i += 2) {
885
- $charval = self::LittleEndian2Int(substr($string, $i, 2));
886
- $newcharstring .= self::iconv_fallback_int_utf8($charval);
887
- }
888
- return $newcharstring;
889
- }
890
-
891
- // UTF-16BE => ISO-8859-1
892
- public static function iconv_fallback_utf16be_iso88591($string) {
893
- if (substr($string, 0, 2) == "\xFE\xFF") {
894
- // strip BOM
895
- $string = substr($string, 2);
896
- }
897
- $newcharstring = '';
898
- for ($i = 0; $i < strlen($string); $i += 2) {
899
- $charval = self::BigEndian2Int(substr($string, $i, 2));
900
- $newcharstring .= (($charval < 256) ? chr($charval) : '?');
901
- }
902
- return $newcharstring;
903
- }
904
-
905
- // UTF-16LE => ISO-8859-1
906
- public static function iconv_fallback_utf16le_iso88591($string) {
907
- if (substr($string, 0, 2) == "\xFF\xFE") {
908
- // strip BOM
909
- $string = substr($string, 2);
910
- }
911
- $newcharstring = '';
912
- for ($i = 0; $i < strlen($string); $i += 2) {
913
- $charval = self::LittleEndian2Int(substr($string, $i, 2));
914
- $newcharstring .= (($charval < 256) ? chr($charval) : '?');
915
- }
916
- return $newcharstring;
917
- }
918
-
919
- // UTF-16 (BOM) => ISO-8859-1
920
- public static function iconv_fallback_utf16_iso88591($string) {
921
- $bom = substr($string, 0, 2);
922
- if ($bom == "\xFE\xFF") {
923
- return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
924
- } elseif ($bom == "\xFF\xFE") {
925
- return self::iconv_fallback_utf16le_iso88591(substr($string, 2));
926
- }
927
- return $string;
928
- }
929
-
930
- // UTF-16 (BOM) => UTF-8
931
- public static function iconv_fallback_utf16_utf8($string) {
932
- $bom = substr($string, 0, 2);
933
- if ($bom == "\xFE\xFF") {
934
- return self::iconv_fallback_utf16be_utf8(substr($string, 2));
935
- } elseif ($bom == "\xFF\xFE") {
936
- return self::iconv_fallback_utf16le_utf8(substr($string, 2));
937
- }
938
- return $string;
939
- }
940
-
941
- public static function iconv_fallback($in_charset, $out_charset, $string) {
942
-
943
- if ($in_charset == $out_charset) {
944
- return $string;
945
- }
946
-
947
- // iconv() availble
948
- if (function_exists('iconv')) {
949
- if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
950
- switch ($out_charset) {
951
- case 'ISO-8859-1':
952
- $converted_string = rtrim($converted_string, "\x00");
953
- break;
954
- }
955
- return $converted_string;
956
- }
957
-
958
- // iconv() may sometimes fail with "illegal character in input string" error message
959
- // and return an empty string, but returning the unconverted string is more useful
960
- return $string;
961
- }
962
-
963
-
964
- // iconv() not available
965
- static $ConversionFunctionList = array();
966
- if (empty($ConversionFunctionList)) {
967
- $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8';
968
- $ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16';
969
- $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be';
970
- $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le';
971
- $ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591';
972
- $ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16';
973
- $ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be';
974
- $ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le';
975
- $ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591';
976
- $ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8';
977
- $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591';
978
- $ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8';
979
- $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591';
980
- $ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8';
981
- }
982
- if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) {
983
- $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
984
- return self::$ConversionFunction($string);
985
- }
986
- throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
987
- }
988
-
989
- public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
990
- if (is_string($data)) {
991
- return self::MultiByteCharString2HTML($data, $charset);
992
- } elseif (is_array($data)) {
993
- $return_data = array();
994
- foreach ($data as $key => $value) {
995
- $return_data[$key] = self::recursiveMultiByteCharString2HTML($value, $charset);
996
- }
997
- return $return_data;
998
- }
999
- // integer, float, objects, resources, etc
1000
- return $data;
1001
- }
1002
-
1003
- public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
1004
- $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
1005
- $HTMLstring = '';
1006
-
1007
- switch ($charset) {
1008
- case '1251':
1009
- case '1252':
1010
- case '866':
1011
- case '932':
1012
- case '936':
1013
- case '950':
1014
- case 'BIG5':
1015
- case 'BIG5-HKSCS':
1016
- case 'cp1251':
1017
- case 'cp1252':
1018
- case 'cp866':
1019
- case 'EUC-JP':
1020
- case 'EUCJP':
1021
- case 'GB2312':
1022
- case 'ibm866':
1023
- case 'ISO-8859-1':
1024
- case 'ISO-8859-15':
1025
- case 'ISO8859-1':
1026
- case 'ISO8859-15':
1027
- case 'KOI8-R':
1028
- case 'koi8-ru':
1029
- case 'koi8r':
1030
- case 'Shift_JIS':
1031
- case 'SJIS':
1032
- case 'win-1251':
1033
- case 'Windows-1251':
1034
- case 'Windows-1252':
1035
- $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
1036
- break;
1037
-
1038
- case 'UTF-8':
1039
- $strlen = strlen($string);
1040
- for ($i = 0; $i < $strlen; $i++) {
1041
- $char_ord_val = ord($string{$i});
1042
- $charval = 0;
1043
- if ($char_ord_val < 0x80) {
1044
- $charval = $char_ord_val;
1045
- } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) {
1046
- $charval = (($char_ord_val & 0x07) << 18);
1047
- $charval += ((ord($string{++$i}) & 0x3F) << 12);
1048
- $charval += ((ord($string{++$i}) & 0x3F) << 6);
1049
- $charval += (ord($string{++$i}) & 0x3F);
1050
- } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) {
1051
- $charval = (($char_ord_val & 0x0F) << 12);
1052
- $charval += ((ord($string{++$i}) & 0x3F) << 6);
1053
- $charval += (ord($string{++$i}) & 0x3F);
1054
- } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) {
1055
- $charval = (($char_ord_val & 0x1F) << 6);
1056
- $charval += (ord($string{++$i}) & 0x3F);
1057
- }
1058
- if (($charval >= 32) && ($charval <= 127)) {
1059
- $HTMLstring .= htmlentities(chr($charval));
1060
- } else {
1061
- $HTMLstring .= '&#'.$charval.';';
1062
- }
1063
- }
1064
- break;
1065
-
1066
- case 'UTF-16LE':
1067
- for ($i = 0; $i < strlen($string); $i += 2) {
1068
- $charval = self::LittleEndian2Int(substr($string, $i, 2));
1069
- if (($charval >= 32) && ($charval <= 127)) {
1070
- $HTMLstring .= chr($charval);
1071
- } else {
1072
- $HTMLstring .= '&#'.$charval.';';
1073
- }
1074
- }
1075
- break;
1076
-
1077
- case 'UTF-16BE':
1078
- for ($i = 0; $i < strlen($string); $i += 2) {
1079
- $charval = self::BigEndian2Int(substr($string, $i, 2));
1080
- if (($charval >= 32) && ($charval <= 127)) {
1081
- $HTMLstring .= chr($charval);
1082
- } else {
1083
- $HTMLstring .= '&#'.$charval.';';
1084
- }
1085
- }
1086
- break;
1087
-
1088
- default:
1089
- $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()';
1090
- break;
1091
- }
1092
- return $HTMLstring;
1093
- }
1094
-
1095
-
1096
-
1097
- public static function RGADnameLookup($namecode) {
1098
- static $RGADname = array();
1099
- if (empty($RGADname)) {
1100
- $RGADname[0] = 'not set';
1101
- $RGADname[1] = 'Track Gain Adjustment';
1102
- $RGADname[2] = 'Album Gain Adjustment';
1103
- }
1104
-
1105
- return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
1106
- }
1107
-
1108
-
1109
- public static function RGADoriginatorLookup($originatorcode) {
1110
- static $RGADoriginator = array();
1111
- if (empty($RGADoriginator)) {
1112
- $RGADoriginator[0] = 'unspecified';
1113
- $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
1114
- $RGADoriginator[2] = 'set by user';
1115
- $RGADoriginator[3] = 'determined automatically';
1116
- }
1117
-
1118
- return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
1119
- }
1120
-
1121
-
1122
- public static function RGADadjustmentLookup($rawadjustment, $signbit) {
1123
- $adjustment = $rawadjustment / 10;
1124
- if ($signbit == 1) {
1125
- $adjustment *= -1;
1126
- }
1127
- return (float) $adjustment;
1128
- }
1129
-
1130
-
1131
- public static function RGADgainString($namecode, $originatorcode, $replaygain) {
1132
- if ($replaygain < 0) {
1133
- $signbit = '1';
1134
- } else {
1135
- $signbit = '0';
1136
- }
1137
- $storedreplaygain = intval(round($replaygain * 10));
1138
- $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT);
1139
- $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT);
1140
- $gainstring .= $signbit;
1141
- $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT);
1142
-
1143
- return $gainstring;
1144
- }
1145
-
1146
- public static function RGADamplitude2dB($amplitude) {
1147
- return 20 * log10($amplitude);
1148
- }
1149
-
1150
-
1151
- public static function GetDataImageSize($imgData, &$imageinfo=array()) {
1152
- static $tempdir = '';
1153
- if (empty($tempdir)) {
1154
- // yes this is ugly, feel free to suggest a better way
1155
- require_once(dirname(__FILE__).'/getid3.php');
1156
- $getid3_temp = new getID3();
1157
- $tempdir = $getid3_temp->tempdir;
1158
- unset($getid3_temp);
1159
- }
1160
- $GetDataImageSize = false;
1161
- if ($tempfilename = tempnam($tempdir, 'gI3')) {
1162
- if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
1163
- fwrite($tmp, $imgData);
1164
- fclose($tmp);
1165
- $GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
1166
- }
1167
- unlink($tempfilename);
1168
- }
1169
- return $GetDataImageSize;
1170
- }
1171
-
1172
- public static function ImageExtFromMime($mime_type) {
1173
- // temporary way, works OK for now, but should be reworked in the future
1174
- return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
1175
- }
1176
-
1177
- public static function ImageTypesLookup($imagetypeid) {
1178
- static $ImageTypesLookup = array();
1179
- if (empty($ImageTypesLookup)) {
1180
- $ImageTypesLookup[1] = 'gif';
1181
- $ImageTypesLookup[2] = 'jpeg';
1182
- $ImageTypesLookup[3] = 'png';
1183
- $ImageTypesLookup[4] = 'swf';
1184
- $ImageTypesLookup[5] = 'psd';
1185
- $ImageTypesLookup[6] = 'bmp';
1186
- $ImageTypesLookup[7] = 'tiff (little-endian)';
1187
- $ImageTypesLookup[8] = 'tiff (big-endian)';
1188
- $ImageTypesLookup[9] = 'jpc';
1189
- $ImageTypesLookup[10] = 'jp2';
1190
- $ImageTypesLookup[11] = 'jpx';
1191
- $ImageTypesLookup[12] = 'jb2';
1192
- $ImageTypesLookup[13] = 'swc';
1193
- $ImageTypesLookup[14] = 'iff';
1194
- }
1195
- return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : '');
1196
- }
1197
-
1198
- public static function CopyTagsToComments(&$ThisFileInfo) {
1199
-
1200
- // Copy all entries from ['tags'] into common ['comments']
1201
- if (!empty($ThisFileInfo['tags'])) {
1202
- foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
1203
- foreach ($tagarray as $tagname => $tagdata) {
1204
- foreach ($tagdata as $key => $value) {
1205
- if (!empty($value)) {
1206
- if (empty($ThisFileInfo['comments'][$tagname])) {
1207
-
1208
- // fall through and append value
1209
-
1210
- } elseif ($tagtype == 'id3v1') {
1211
-
1212
- $newvaluelength = strlen(trim($value));
1213
- foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
1214
- $oldvaluelength = strlen(trim($existingvalue));
1215
- if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) {
1216
- // new value is identical but shorter-than (or equal-length to) one already in comments - skip
1217
- break 2;
1218
- }
1219
- }
1220
-
1221
- } elseif (!is_array($value)) {
1222
-
1223
- $newvaluelength = strlen(trim($value));
1224
- foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
1225
- $oldvaluelength = strlen(trim($existingvalue));
1226
- if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
1227
- $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
1228
- //break 2;
1229
- break;
1230
- }
1231
- }
1232
-
1233
- }
1234
- if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
1235
- $value = (is_string($value) ? trim($value) : $value);
1236
- if (!is_numeric($key)) {
1237
- $ThisFileInfo['comments'][$tagname][$key] = $value;
1238
- } else {
1239
- $ThisFileInfo['comments'][$tagname][] = $value;
1240
- }
1241
- }
1242
- }
1243
- }
1244
- }
1245
- }
1246
-
1247
- // Copy to ['comments_html']
1248
- if (!empty($ThisFileInfo['comments'])) {
1249
- foreach ($ThisFileInfo['comments'] as $field => $values) {
1250
- if ($field == 'picture') {
1251
- // pictures can take up a lot of space, and we don't need multiple copies of them
1252
- // let there be a single copy in [comments][picture], and not elsewhere
1253
- continue;
1254
- }
1255
- foreach ($values as $index => $value) {
1256
- if (is_array($value)) {
1257
- $ThisFileInfo['comments_html'][$field][$index] = $value;
1258
- } else {
1259
- $ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
1260
- }
1261
- }
1262
- }
1263
- }
1264
-
1265
- }
1266
- return true;
1267
- }
1268
-
1269
-
1270
- public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
1271
-
1272
- // Cached
1273
- static $cache;
1274
- if (isset($cache[$file][$name])) {
1275
- return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
1276
- }
1277
-
1278
- // Init
1279
- $keylength = strlen($key);
1280
- $line_count = $end - $begin - 7;
1281
-
1282
- // Open php file
1283
- $fp = fopen($file, 'r');
1284
-
1285
- // Discard $begin lines
1286
- for ($i = 0; $i < ($begin + 3); $i++) {
1287
- fgets($fp, 1024);
1288
- }
1289
-
1290
- // Loop thru line
1291
- while (0 < $line_count--) {
1292
-
1293
- // Read line
1294
- $line = ltrim(fgets($fp, 1024), "\t ");
1295
-
1296
- // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key
1297
- //$keycheck = substr($line, 0, $keylength);
1298
- //if ($key == $keycheck) {
1299
- // $cache[$file][$name][$keycheck] = substr($line, $keylength + 1);
1300
- // break;
1301
- //}
1302
-
1303
- // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key
1304
- //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1));
1305
- $explodedLine = explode("\t", $line, 2);
1306
- $ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : '');
1307
- $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : '');
1308
- $cache[$file][$name][$ThisKey] = trim($ThisValue);
1309
- }
1310
-
1311
- // Close and return
1312
- fclose($fp);
1313
- return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
1314
- }
1315
-
1316
- public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
1317
- global $GETID3_ERRORARRAY;
1318
-
1319
- if (file_exists($filename)) {
1320
- if (include_once($filename)) {
1321
- return true;
1322
- } else {
1323
- $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors';
1324
- }
1325
- } else {
1326
- $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing';
1327
- }
1328
- if ($DieOnFailure) {
1329
- throw new Exception($diemessage);
1330
- } else {
1331
- $GETID3_ERRORARRAY[] = $diemessage;
1332
- }
1333
- return false;
1334
- }
1335
-
1336
- public static function trimNullByte($string) {
1337
- return trim($string, "\x00");
1338
- }
1339
-
1340
- public static function getFileSizeSyscall($path) {
1341
- $filesize = false;
1342
-
1343
- if (GETID3_OS_ISWINDOWS) {
1344
- if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini:
1345
- $filesystem = new COM('Scripting.FileSystemObject');
1346
- $file = $filesystem->GetFile($path);
1347
- $filesize = $file->Size();
1348
- unset($filesystem, $file);
1349
- } else {
1350
- $commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI';
1351
- }
1352
- } else {
1353
- $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\'';
1354
- }
1355
- if (isset($commandline)) {
1356
- $output = trim(`$commandline`);
1357
- if (ctype_digit($output)) {
1358
- $filesize = (float) $output;
1359
- }
1360
- }
1361
- return $filesize;
1362
- }
1363
-
1364
-
1365
- /**
1366
- * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
1367
- * @param string $path A path.
1368
- * @param string $suffix If the name component ends in suffix this will also be cut off.
1369
- * @return string
1370
- */
1371
- public static function mb_basename($path, $suffix = null) {
1372
- $splited = preg_split('#/#', rtrim($path, '/ '));
1373
- return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
1374
- }
1375
-
1376
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /////////////////////////////////////////////////////////////////
3
+ /// getID3() by James Heinrich <info@getid3.org> //
4
+ // available at http://getid3.sourceforge.net //
5
+ // or http://www.getid3.org //
6
+ // also https://github.com/JamesHeinrich/getID3 //
7
+ /////////////////////////////////////////////////////////////////
8
+ // //
9
+ // getid3.lib.php - part of getID3() //
10
+ // See readme.txt for more details //
11
+ // ///
12
+ /////////////////////////////////////////////////////////////////
13
+
14
+
15
+ class getid3_lib
16
+ {
17
+
18
+ public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
19
+ $returnstring = '';
20
+ for ($i = 0; $i < strlen($string); $i++) {
21
+ if ($hex) {
22
+ $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
23
+ } else {
24
+ $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤');
25
+ }
26
+ if ($spaces) {
27
+ $returnstring .= ' ';
28
+ }
29
+ }
30
+ if (!empty($htmlencoding)) {
31
+ if ($htmlencoding === true) {
32
+ $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean
33
+ }
34
+ $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
35
+ }
36
+ return $returnstring;
37
+ }
38
+
39
+ public static function trunc($floatnumber) {
40
+ // truncates a floating-point number at the decimal point
41
+ // returns int (if possible, otherwise float)
42
+ if ($floatnumber >= 1) {
43
+ $truncatednumber = floor($floatnumber);
44
+ } elseif ($floatnumber <= -1) {
45
+ $truncatednumber = ceil($floatnumber);
46
+ } else {
47
+ $truncatednumber = 0;
48
+ }
49
+ if (self::intValueSupported($truncatednumber)) {
50
+ $truncatednumber = (int) $truncatednumber;
51
+ }
52
+ return $truncatednumber;
53
+ }
54
+
55
+
56
+ public static function safe_inc(&$variable, $increment=1) {
57
+ if (isset($variable)) {
58
+ $variable += $increment;
59
+ } else {
60
+ $variable = $increment;
61
+ }
62
+ return true;
63
+ }
64
+
65
+ public static function CastAsInt($floatnum) {
66
+ // convert to float if not already
67
+ $floatnum = (float) $floatnum;
68
+
69
+ // convert a float to type int, only if possible
70
+ if (self::trunc($floatnum) == $floatnum) {
71
+ // it's not floating point
72
+ if (self::intValueSupported($floatnum)) {
73
+ // it's within int range
74
+ $floatnum = (int) $floatnum;
75
+ }
76
+ }
77
+ return $floatnum;
78
+ }
79
+
80
+ public static function intValueSupported($num) {
81
+ // check if integers are 64-bit
82
+ static $hasINT64 = null;
83
+ if ($hasINT64 === null) { // 10x faster than is_null()
84
+ $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
85
+ if (!$hasINT64 && !defined('PHP_INT_MIN')) {
86
+ define('PHP_INT_MIN', ~PHP_INT_MAX);
87
+ }
88
+ }
89
+ // if integers are 64-bit - no other check required
90
+ if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
91
+ return true;
92
+ }
93
+ return false;
94
+ }
95
+
96
+ public static function DecimalizeFraction($fraction) {
97
+ list($numerator, $denominator) = explode('/', $fraction);
98
+ return $numerator / ($denominator ? $denominator : 1);
99
+ }
100
+
101
+
102
+ public static function DecimalBinary2Float($binarynumerator) {
103
+ $numerator = self::Bin2Dec($binarynumerator);
104
+ $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
105
+ return ($numerator / $denominator);
106
+ }
107
+
108
+
109
+ public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
110
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
111
+ if (strpos($binarypointnumber, '.') === false) {
112
+ $binarypointnumber = '0.'.$binarypointnumber;
113
+ } elseif ($binarypointnumber{0} == '.') {
114
+ $binarypointnumber = '0'.$binarypointnumber;
115
+ }
116
+ $exponent = 0;
117
+ while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
118
+ if (substr($binarypointnumber, 1, 1) == '.') {
119
+ $exponent--;
120
+ $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
121
+ } else {
122
+ $pointpos = strpos($binarypointnumber, '.');
123
+ $exponent += ($pointpos - 1);
124
+ $binarypointnumber = str_replace('.', '', $binarypointnumber);
125
+ $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
126
+ }
127
+ }
128
+ $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
129
+ return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
130
+ }
131
+
132
+
133
+ public static function Float2BinaryDecimal($floatvalue) {
134
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
135
+ $maxbits = 128; // to how many bits of precision should the calculations be taken?
136
+ $intpart = self::trunc($floatvalue);
137
+ $floatpart = abs($floatvalue - $intpart);
138
+ $pointbitstring = '';
139
+ while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
140
+ $floatpart *= 2;
141
+ $pointbitstring .= (string) self::trunc($floatpart);
142
+ $floatpart -= self::trunc($floatpart);
143
+ }
144
+ $binarypointnumber = decbin($intpart).'.'.$pointbitstring;
145
+ return $binarypointnumber;
146
+ }
147
+
148
+
149
+ public static function Float2String($floatvalue, $bits) {
150
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
151
+ switch ($bits) {
152
+ case 32:
153
+ $exponentbits = 8;
154
+ $fractionbits = 23;
155
+ break;
156
+
157
+ case 64:
158
+ $exponentbits = 11;
159
+ $fractionbits = 52;
160
+ break;
161
+
162
+ default:
163
+ return false;
164
+ break;
165
+ }
166
+ if ($floatvalue >= 0) {
167
+ $signbit = '0';
168
+ } else {
169
+ $signbit = '1';
170
+ }
171
+ $normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits);
172
+ $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
173
+ $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
174
+ $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
175
+
176
+ return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
177
+ }
178
+
179
+
180
+ public static function LittleEndian2Float($byteword) {
181
+ return self::BigEndian2Float(strrev($byteword));
182
+ }
183
+
184
+
185
+ public static function BigEndian2Float($byteword) {
186
+ // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
187
+ // http://www.psc.edu/general/software/packages/ieee/ieee.html
188
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
189
+
190
+ $bitword = self::BigEndian2Bin($byteword);
191
+ if (!$bitword) {
192
+ return 0;
193
+ }
194
+ $signbit = $bitword{0};
195
+
196
+ switch (strlen($byteword) * 8) {
197
+ case 32:
198
+ $exponentbits = 8;
199
+ $fractionbits = 23;
200
+ break;
201
+
202
+ case 64:
203
+ $exponentbits = 11;
204
+ $fractionbits = 52;
205
+ break;
206
+
207
+ case 80:
208
+ // 80-bit Apple SANE format
209
+ // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
210
+ $exponentstring = substr($bitword, 1, 15);
211
+ $isnormalized = intval($bitword{16});
212
+ $fractionstring = substr($bitword, 17, 63);
213
+ $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
214
+ $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
215
+ $floatvalue = $exponent * $fraction;
216
+ if ($signbit == '1') {
217
+ $floatvalue *= -1;
218
+ }
219
+ return $floatvalue;
220
+ break;
221
+
222
+ default:
223
+ return false;
224
+ break;
225
+ }
226
+ $exponentstring = substr($bitword, 1, $exponentbits);
227
+ $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
228
+ $exponent = self::Bin2Dec($exponentstring);
229
+ $fraction = self::Bin2Dec($fractionstring);
230
+
231
+ if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
232
+ // Not a Number
233
+ $floatvalue = false;
234
+ } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
235
+ if ($signbit == '1') {
236
+ $floatvalue = '-infinity';
237
+ } else {
238
+ $floatvalue = '+infinity';
239
+ }
240
+ } elseif (($exponent == 0) && ($fraction == 0)) {
241
+ if ($signbit == '1') {
242
+ $floatvalue = -0;
243
+ } else {
244
+ $floatvalue = 0;
245
+ }
246
+ $floatvalue = ($signbit ? 0 : -0);
247
+ } elseif (($exponent == 0) && ($fraction != 0)) {
248
+ // These are 'unnormalized' values
249
+ $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring);
250
+ if ($signbit == '1') {
251
+ $floatvalue *= -1;
252
+ }
253
+ } elseif ($exponent != 0) {
254
+ $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring));
255
+ if ($signbit == '1') {
256
+ $floatvalue *= -1;
257
+ }
258
+ }
259
+ return (float) $floatvalue;
260
+ }
261
+
262
+
263
+ public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
264
+ $intvalue = 0;
265
+ $bytewordlen = strlen($byteword);
266
+ if ($bytewordlen == 0) {
267
+ return false;
268
+ }
269
+ for ($i = 0; $i < $bytewordlen; $i++) {
270
+ if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
271
+ //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
272
+ $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
273
+ } else {
274
+ $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
275
+ }
276
+ }
277
+ if ($signed && !$synchsafe) {
278
+ // synchsafe ints are not allowed to be signed
279
+ if ($bytewordlen <= PHP_INT_SIZE) {
280
+ $signMaskBit = 0x80 << (8 * ($bytewordlen - 1));
281
+ if ($intvalue & $signMaskBit) {
282
+ $intvalue = 0 - ($intvalue & ($signMaskBit - 1));
283
+ }
284
+ } else {
285
+ throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()');
286
+ }
287
+ }
288
+ return self::CastAsInt($intvalue);
289
+ }
290
+
291
+
292
+ public static function LittleEndian2Int($byteword, $signed=false) {
293
+ return self::BigEndian2Int(strrev($byteword), false, $signed);
294
+ }
295
+
296
+
297
+ public static function BigEndian2Bin($byteword) {
298
+ $binvalue = '';
299
+ $bytewordlen = strlen($byteword);
300
+ for ($i = 0; $i < $bytewordlen; $i++) {
301
+ $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
302
+ }
303
+ return $binvalue;
304
+ }
305
+
306
+
307
+ public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
308
+ if ($number < 0) {
309
+ throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
310
+ }
311
+ $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
312
+ $intstring = '';
313
+ if ($signed) {
314
+ if ($minbytes > PHP_INT_SIZE) {
315
+ throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()');
316
+ }
317
+ $number = $number & (0x80 << (8 * ($minbytes - 1)));
318
+ }
319
+ while ($number != 0) {
320
+ $quotient = ($number / ($maskbyte + 1));
321
+ $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring;
322
+ $number = floor($quotient);
323
+ }
324
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
325
+ }
326
+
327
+
328
+ public static function Dec2Bin($number) {
329
+ while ($number >= 256) {
330
+ $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
331
+ $number = floor($number / 256);
332
+ }
333
+ $bytes[] = $number;
334
+ $binstring = '';
335
+ for ($i = 0; $i < count($bytes); $i++) {
336
+ $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
337
+ }
338
+ return $binstring;
339
+ }
340
+
341
+
342
+ public static function Bin2Dec($binstring, $signed=false) {
343
+ $signmult = 1;
344
+ if ($signed) {
345
+ if ($binstring{0} == '1') {
346
+ $signmult = -1;
347
+ }
348
+ $binstring = substr($binstring, 1);
349
+ }
350
+ $decvalue = 0;
351
+ for ($i = 0; $i < strlen($binstring); $i++) {
352
+ $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
353
+ }
354
+ return self::CastAsInt($decvalue * $signmult);
355
+ }
356
+
357
+
358
+ public static function Bin2String($binstring) {
359
+ // return 'hi' for input of '0110100001101001'
360
+ $string = '';
361
+ $binstringreversed = strrev($binstring);
362
+ for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
363
+ $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
364
+ }
365
+ return $string;
366
+ }
367
+
368
+
369
+ public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
370
+ $intstring = '';
371
+ while ($number > 0) {
372
+ if ($synchsafe) {
373
+ $intstring = $intstring.chr($number & 127);
374
+ $number >>= 7;
375
+ } else {
376
+ $intstring = $intstring.chr($number & 255);
377
+ $number >>= 8;
378
+ }
379
+ }
380
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
381
+ }
382
+
383
+
384
+ public static function array_merge_clobber($array1, $array2) {
385
+ // written by kcØhireability*com
386
+ // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
387
+ if (!is_array($array1) || !is_array($array2)) {
388
+ return false;
389
+ }
390
+ $newarray = $array1;
391
+ foreach ($array2 as $key => $val) {
392
+ if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
393
+ $newarray[$key] = self::array_merge_clobber($newarray[$key], $val);
394
+ } else {
395
+ $newarray[$key] = $val;
396
+ }
397
+ }
398
+ return $newarray;
399
+ }
400
+
401
+
402
+ public static function array_merge_noclobber($array1, $array2) {
403
+ if (!is_array($array1) || !is_array($array2)) {
404
+ return false;
405
+ }
406
+ $newarray = $array1;
407
+ foreach ($array2 as $key => $val) {
408
+ if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
409
+ $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val);
410
+ } elseif (!isset($newarray[$key])) {
411
+ $newarray[$key] = $val;
412
+ }
413
+ }
414
+ return $newarray;
415
+ }
416
+
417
+ public static function flipped_array_merge_noclobber($array1, $array2) {
418
+ if (!is_array($array1) || !is_array($array2)) {
419
+ return false;
420
+ }
421
+ # naturally, this only works non-recursively
422
+ $newarray = array_flip($array1);
423
+ foreach (array_flip($array2) as $key => $val) {
424
+ if (!isset($newarray[$key])) {
425
+ $newarray[$key] = count($newarray);
426
+ }
427
+ }
428
+ return array_flip($newarray);
429
+ }
430
+
431
+
432
+ public static function ksort_recursive(&$theArray) {
433
+ ksort($theArray);
434
+ foreach ($theArray as $key => $value) {
435
+ if (is_array($value)) {
436
+ self::ksort_recursive($theArray[$key]);
437
+ }
438
+ }
439
+ return true;
440
+ }
441
+
442
+ public static function fileextension($filename, $numextensions=1) {
443
+ if (strstr($filename, '.')) {
444
+ $reversedfilename = strrev($filename);
445
+ $offset = 0;
446
+ for ($i = 0; $i < $numextensions; $i++) {
447
+ $offset = strpos($reversedfilename, '.', $offset + 1);
448
+ if ($offset === false) {
449
+ return '';
450
+ }
451
+ }
452
+ return strrev(substr($reversedfilename, 0, $offset));
453
+ }
454
+ return '';
455
+ }
456
+
457
+
458
+ public static function PlaytimeString($seconds) {
459
+ $sign = (($seconds < 0) ? '-' : '');
460
+ $seconds = round(abs($seconds));
461
+ $H = (int) floor( $seconds / 3600);
462
+ $M = (int) floor(($seconds - (3600 * $H) ) / 60);
463
+ $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
464
+ return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
465
+ }
466
+
467
+
468
+ public static function DateMac2Unix($macdate) {
469
+ // Macintosh timestamp: seconds since 00:00h January 1, 1904
470
+ // UNIX timestamp: seconds since 00:00h January 1, 1970
471
+ return self::CastAsInt($macdate - 2082844800);
472
+ }
473
+
474
+
475
+ public static function FixedPoint8_8($rawdata) {
476
+ return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
477
+ }
478
+
479
+
480
+ public static function FixedPoint16_16($rawdata) {
481
+ return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
482
+ }
483
+
484
+
485
+ public static function FixedPoint2_30($rawdata) {
486
+ $binarystring = self::BigEndian2Bin($rawdata);
487
+ return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
488
+ }
489
+
490
+
491
+ public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
492
+ // assigns $Value to a nested array path:
493
+ // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
494
+ // is the same as:
495
+ // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
496
+ // or
497
+ // $foo['path']['to']['my'] = 'file.txt';
498
+ $ArrayPath = ltrim($ArrayPath, $Separator);
499
+ if (($pos = strpos($ArrayPath, $Separator)) !== false) {
500
+ $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
501
+ } else {
502
+ $ReturnedArray[$ArrayPath] = $Value;
503
+ }
504
+ return $ReturnedArray;
505
+ }
506
+
507
+ public static function array_max($arraydata, $returnkey=false) {
508
+ $maxvalue = false;
509
+ $maxkey = false;
510
+ foreach ($arraydata as $key => $value) {
511
+ if (!is_array($value)) {
512
+ if ($value > $maxvalue) {
513
+ $maxvalue = $value;
514
+ $maxkey = $key;
515
+ }
516
+ }
517
+ }
518
+ return ($returnkey ? $maxkey : $maxvalue);
519
+ }
520
+
521
+ public static function array_min($arraydata, $returnkey=false) {
522
+ $minvalue = false;
523
+ $minkey = false;
524
+ foreach ($arraydata as $key => $value) {
525
+ if (!is_array($value)) {
526
+ if ($value > $minvalue) {
527
+ $minvalue = $value;
528
+ $minkey = $key;
529
+ }
530
+ }
531
+ }
532
+ return ($returnkey ? $minkey : $minvalue);
533
+ }
534
+
535
+ public static function XML2array($XMLstring) {
536
+ if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
537
+ // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
538
+ // https://core.trac.wordpress.org/changeset/29378
539
+ $loader = libxml_disable_entity_loader(true);
540
+ $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT);
541
+ $return = self::SimpleXMLelement2array($XMLobject);
542
+ libxml_disable_entity_loader($loader);
543
+ return $return;
544
+ }
545
+ return false;
546
+ }
547
+
548
+ public static function SimpleXMLelement2array($XMLobject) {
549
+ if (!is_object($XMLobject) && !is_array($XMLobject)) {
550
+ return $XMLobject;
551
+ }
552
+ $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
553
+ foreach ($XMLarray as $key => $value) {
554
+ $XMLarray[$key] = self::SimpleXMLelement2array($value);
555
+ }
556
+ return $XMLarray;
557
+ }
558
+
559
+
560
+ // Allan Hansen <ahØartemis*dk>
561
+ // self::md5_data() - returns md5sum for a file from startuing position to absolute end position
562
+ public static function hash_data($file, $offset, $end, $algorithm) {
563
+ static $tempdir = '';
564
+ if (!self::intValueSupported($end)) {
565
+ return false;
566
+ }
567
+ switch ($algorithm) {
568
+ case 'md5':
569
+ $hash_function = 'md5_file';
570
+ $unix_call = 'md5sum';
571
+ $windows_call = 'md5sum.exe';
572
+ $hash_length = 32;
573
+ break;
574
+
575
+ case 'sha1':
576
+ $hash_function = 'sha1_file';
577
+ $unix_call = 'sha1sum';
578
+ $windows_call = 'sha1sum.exe';
579
+ $hash_length = 40;
580
+ break;
581
+
582
+ default:
583
+ throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
584
+ break;
585
+ }
586
+ $size = $end - $offset;
587
+ while (true) {
588
+ if (GETID3_OS_ISWINDOWS) {
589
+
590
+ // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
591
+ // Fall back to create-temp-file method:
592
+ if ($algorithm == 'sha1') {
593
+ break;
594
+ }
595
+
596
+ $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
597
+ foreach ($RequiredFiles as $required_file) {
598
+ if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
599
+ // helper apps not available - fall back to old method
600
+ break 2;
601
+ }
602
+ }
603
+ $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
604
+ $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
605
+ $commandline .= GETID3_HELPERAPPSDIR.$windows_call;
606
+
607
+ } else {
608
+
609
+ $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
610
+ $commandline .= 'tail -c'.$size.' | ';
611
+ $commandline .= $unix_call;
612
+
613
+ }
614
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
615
+ //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
616
+ break;
617
+ }
618
+ return substr(`$commandline`, 0, $hash_length);
619
+ }
620
+
621
+ if (empty($tempdir)) {
622
+ // yes this is ugly, feel free to suggest a better way
623
+ require_once(dirname(__FILE__).'/getid3.php');
624
+ $getid3_temp = new getID3();
625
+ $tempdir = $getid3_temp->tempdir;
626
+ unset($getid3_temp);
627
+ }
628
+ // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
629
+ if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
630
+ // can't find anywhere to create a temp file, just fail
631
+ return false;
632
+ }
633
+
634
+ // Init
635
+ $result = false;
636
+
637
+ // copy parts of file
638
+ try {
639
+ self::CopyFileParts($file, $data_filename, $offset, $end - $offset);
640
+ $result = $hash_function($data_filename);
641
+ } catch (Exception $e) {
642
+ throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
643
+ }
644
+ unlink($data_filename);
645
+ return $result;
646
+ }
647
+
648
+ public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
649
+ if (!self::intValueSupported($offset + $length)) {
650
+ throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
651
+ }
652
+ if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
653
+ if (($fp_dest = fopen($filename_dest, 'wb'))) {
654
+ if (fseek($fp_src, $offset) == 0) {
655
+ $byteslefttowrite = $length;
656
+ while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
657
+ $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
658
+ $byteslefttowrite -= $byteswritten;
659
+ }
660
+ return true;
661
+ } else {
662
+ throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
663
+ }
664
+ fclose($fp_dest);
665
+ } else {
666
+ throw new Exception('failed to create file for writing '.$filename_dest);
667
+ }
668
+ fclose($fp_src);
669
+ } else {
670
+ throw new Exception('failed to open file for reading '.$filename_source);
671
+ }
672
+ return false;
673
+ }
674
+
675
+ public static function iconv_fallback_int_utf8($charval) {
676
+ if ($charval < 128) {
677
+ // 0bbbbbbb
678
+ $newcharstring = chr($charval);
679
+ } elseif ($charval < 2048) {
680
+ // 110bbbbb 10bbbbbb
681
+ $newcharstring = chr(($charval >> 6) | 0xC0);
682
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
683
+ } elseif ($charval < 65536) {
684
+ // 1110bbbb 10bbbbbb 10bbbbbb
685
+ $newcharstring = chr(($charval >> 12) | 0xE0);
686
+ $newcharstring .= chr(($charval >> 6) | 0xC0);
687
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
688
+ } else {
689
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
690
+ $newcharstring = chr(($charval >> 18) | 0xF0);
691
+ $newcharstring .= chr(($charval >> 12) | 0xC0);
692
+ $newcharstring .= chr(($charval >> 6) | 0xC0);
693
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
694
+ }
695
+ return $newcharstring;
696
+ }
697
+
698
+ // ISO-8859-1 => UTF-8
699
+ public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
700
+ if (function_exists('utf8_encode')) {
701
+ return utf8_encode($string);
702
+ }
703
+ // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
704
+ $newcharstring = '';
705
+ if ($bom) {
706
+ $newcharstring .= "\xEF\xBB\xBF";
707
+ }
708
+ for ($i = 0; $i < strlen($string); $i++) {
709
+ $charval = ord($string{$i});
710
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
711
+ }
712
+ return $newcharstring;
713
+ }
714
+
715
+ // ISO-8859-1 => UTF-16BE
716
+ public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
717
+ $newcharstring = '';
718
+ if ($bom) {
719
+ $newcharstring .= "\xFE\xFF";
720
+ }
721
+ for ($i = 0; $i < strlen($string); $i++) {
722
+ $newcharstring .= "\x00".$string{$i};
723
+ }
724
+ return $newcharstring;
725
+ }
726
+
727
+ // ISO-8859-1 => UTF-16LE
728
+ public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
729
+ $newcharstring = '';
730
+ if ($bom) {
731
+ $newcharstring .= "\xFF\xFE";
732
+ }
733
+ for ($i = 0; $i < strlen($string); $i++) {
734
+ $newcharstring .= $string{$i}."\x00";
735
+ }
736
+ return $newcharstring;
737
+ }
738
+
739
+ // ISO-8859-1 => UTF-16LE (BOM)
740
+ public static function iconv_fallback_iso88591_utf16($string) {
741
+ return self::iconv_fallback_iso88591_utf16le($string, true);
742
+ }
743
+
744
+ // UTF-8 => ISO-8859-1
745
+ public static function iconv_fallback_utf8_iso88591($string) {
746
+ if (function_exists('utf8_decode')) {
747
+ return utf8_decode($string);
748
+ }
749
+ // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
750
+ $newcharstring = '';
751
+ $offset = 0;
752
+ $stringlength = strlen($string);
753
+ while ($offset < $stringlength) {
754
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
755
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
756
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
757
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
758
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
759
+ (ord($string{($offset + 3)}) & 0x3F);
760
+ $offset += 4;
761
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
762
+ // 1110bbbb 10bbbbbb 10bbbbbb
763
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
764
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
765
+ (ord($string{($offset + 2)}) & 0x3F);
766
+ $offset += 3;
767
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
768
+ // 110bbbbb 10bbbbbb
769
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
770
+ (ord($string{($offset + 1)}) & 0x3F);
771
+ $offset += 2;
772
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
773
+ // 0bbbbbbb
774
+ $charval = ord($string{$offset});
775
+ $offset += 1;
776
+ } else {
777
+ // error? throw some kind of warning here?
778
+ $charval = false;
779
+ $offset += 1;
780
+ }
781
+ if ($charval !== false) {
782