303 {
305 return false;
306 }
307 $framedata = '';
308
309 if (($this->majorversion < 3) || ($this->majorversion > 4)) {
310
311 $this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()';
312
313 } else {
314
315 switch ($frame_name) {
316 case 'UFID':
317
318
319
320 if (strlen($source_data_array['data']) > 64) {
321 $this->errors[] = 'Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($source_data_array['data']).' bytes long)';
322 } else {
323 $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
324 $framedata .= substr($source_data_array['data'], 0, 64);
325 }
326 break;
327
328 case 'TXXX':
329
330
331
332
335 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
336 } else {
337 $framedata .= chr($source_data_array['encodingid']);
338 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
339 $framedata .= $source_data_array['data'];
340 }
341 break;
342
343 case 'WXXX':
344
345
346
347
350 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
351 } elseif (!isset($source_data_array[
'data']) || !$this->
IsValidURL($source_data_array[
'data'],
false,
false)) {
352
353
354 $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
355 } else {
356 $framedata .= chr($source_data_array['encodingid']);
357 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
358 $framedata .= $source_data_array['data'];
359 }
360 break;
361
362 case 'IPLS':
363
364
365
368 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
369 } else {
370 $framedata .= chr($source_data_array['encodingid']);
371 $framedata .= $source_data_array['data'];
372 }
373 break;
374
375 case 'MCDI':
376
377
378 $framedata .= $source_data_array['data'];
379 break;
380
381 case 'ETCO':
382
383
384
385
386
387
388
389
390
391
392 if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
393 $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')';
394 } else {
395 $framedata .= chr($source_data_array['timestampformat']);
396 foreach ($source_data_array as
$key => $val) {
398 $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')';
399 } elseif ((
$key !=
'timestampformat') && (
$key !=
'flags')) {
400 if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) {
401
402
403 $this->errors[] = 'Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')';
404 } else {
405 $framedata .= chr($val['typeid']);
407 }
408 }
409 }
410 }
411 break;
412
413 case 'MLLT':
414
415
416
417
418
419
420
421
422
423 if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535)) {
425 } else {
426 $this->errors[] = 'Invalid MPEG Frames Between References in '.$frame_name.' ('.$source_data_array['framesbetweenreferences'].')';
427 }
428 if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215)) {
430 } else {
431 $this->errors[] = 'Invalid bytes Between References in '.$frame_name.' ('.$source_data_array['bytesbetweenreferences'].')';
432 }
433 if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215)) {
435 } else {
436 $this->errors[] = 'Invalid Milliseconds Between References in '.$frame_name.' ('.$source_data_array['msbetweenreferences'].')';
437 }
438 if (!$this->
IsWithinBitRange($source_data_array[
'bitsforbytesdeviation'], 8,
false)) {
439 if (($source_data_array['bitsforbytesdeviation'] % 4) == 0) {
440 $framedata .= chr($source_data_array['bitsforbytesdeviation']);
441 } else {
442 $this->errors[] = 'Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.';
443 }
444 } else {
445 $this->errors[] = 'Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].')';
446 }
447 if (!$this->
IsWithinBitRange($source_data_array[
'bitsformsdeviation'], 8,
false)) {
448 if (($source_data_array['bitsformsdeviation'] % 4) == 0) {
449 $framedata .= chr($source_data_array['bitsformsdeviation']);
450 } else {
451 $this->errors[] = 'Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.';
452 }
453 } else {
454 $this->errors[] = 'Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsformsdeviation'].')';
455 }
456 foreach ($source_data_array as
$key => $val) {
457 if ((
$key !=
'framesbetweenreferences') && (
$key !=
'bytesbetweenreferences') && (
$key !=
'msbetweenreferences') && (
$key !=
'bitsforbytesdeviation') && (
$key !=
'bitsformsdeviation') && (
$key !=
'flags')) {
458 $unwrittenbitstream .= str_pad(
getid3_lib::Dec2Bin($val[
'bytedeviation']), $source_data_array[
'bitsforbytesdeviation'],
'0', STR_PAD_LEFT);
459 $unwrittenbitstream .= str_pad(
getid3_lib::Dec2Bin($val[
'msdeviation']), $source_data_array[
'bitsformsdeviation'],
'0', STR_PAD_LEFT);
460 }
461 }
462 for (
$i = 0;
$i < strlen($unwrittenbitstream);
$i += 8) {
463 $highnibble = bindec(substr($unwrittenbitstream,
$i, 4)) << 4;
464 $lownibble = bindec(substr($unwrittenbitstream,
$i + 4, 4));
465 $framedata .= chr($highnibble & $lownibble);
466 }
467 break;
468
469 case 'SYTC':
470
471
472
473
474
475
476 if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
477 $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')';
478 } else {
479 $framedata .= chr($source_data_array['timestampformat']);
480 foreach ($source_data_array as
$key => $val) {
482 $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')';
483 } elseif ((
$key !=
'timestampformat') && (
$key !=
'flags')) {
484 if (($val['tempo'] < 0) || ($val['tempo'] > 510)) {
485 $this->errors[] = 'Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')';
486 } else {
487 if ($val['tempo'] > 255) {
488 $framedata .= chr(255);
489 $val['tempo'] -= 255;
490 }
491 $framedata .= chr($val['tempo']);
493 }
494 }
495 }
496 }
497 break;
498
499 case 'USLT':
500
501
502
503
504
507 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
509 $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
510 } else {
511 $framedata .= chr($source_data_array['encodingid']);
512 $framedata .= strtolower($source_data_array['language']);
513 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
514 $framedata .= $source_data_array['data'];
515 }
516 break;
517
518 case 'SYLT':
519
520
521
522
523
524
525
526
527
528
529
532 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
534 $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
535 } elseif (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
536 $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')';
538 $this->errors[] = 'Invalid Content Type byte in '.$frame_name.' ('.$source_data_array['contenttypeid'].')';
539 } elseif (!is_array($source_data_array['data'])) {
540 $this->errors[] = 'Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)';
541 } else {
542 $framedata .= chr($source_data_array['encodingid']);
543 $framedata .= strtolower($source_data_array['language']);
544 $framedata .= chr($source_data_array['timestampformat']);
545 $framedata .= chr($source_data_array['contenttypeid']);
546 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
547 ksort($source_data_array['data']);
548 foreach ($source_data_array[
'data'] as
$key => $val) {
549 $framedata .= $val['data'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
551 }
552 }
553 break;
554
555 case 'COMM':
556
557
558
559
560
563 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
565 $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
566 } else {
567 $framedata .= chr($source_data_array['encodingid']);
568 $framedata .= strtolower($source_data_array['language']);
569 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
570 $framedata .= $source_data_array['data'];
571 }
572 break;
573
574 case 'RVA2':
575
576
577
578
579
580
581
582
583
584 $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00";
585 foreach ($source_data_array as
$key => $val) {
586 if (
$key !=
'description') {
587 $framedata .= chr($val['channeltypeid']);
589 if (!$this->
IsWithinBitRange($source_data_array[
'bitspeakvolume'], 8,
false)) {
590 $framedata .= chr($val['bitspeakvolume']);
591 if ($val['bitspeakvolume'] > 0) {
593 }
594 } else {
595 $this->errors[] = 'Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)';
596 }
597 }
598 }
599 break;
600
601 case 'RVAD':
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
618 $this->errors[] = 'Invalid Bits For Volume Description byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)';
619 } else {
620 $incdecflag .= '00';
621 $incdecflag .= $source_data_array['incdec']['right'] ? '1' : '0';
622 $incdecflag .= $source_data_array['incdec']['left'] ? '1' : '0';
623 $incdecflag .= $source_data_array['incdec']['rightrear'] ? '1' : '0';
624 $incdecflag .= $source_data_array['incdec']['leftrear'] ? '1' : '0';
625 $incdecflag .= $source_data_array['incdec']['center'] ? '1' : '0';
626 $incdecflag .= $source_data_array['incdec']['bass'] ? '1' : '0';
627 $framedata .= chr(bindec($incdecflag));
628 $framedata .= chr($source_data_array['bitsvolume']);
629 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'volumechange'][
'right'], ceil($source_data_array[
'bitsvolume'] / 8),
false);
630 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'volumechange'][
'left'], ceil($source_data_array[
'bitsvolume'] / 8),
false);
631 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'peakvolume'][
'right'], ceil($source_data_array[
'bitsvolume'] / 8),
false);
632 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'peakvolume'][
'left'], ceil($source_data_array[
'bitsvolume'] / 8),
false);
633 if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] ||
634 $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] ||
635 $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] ||
636 $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
637 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'volumechange'][
'rightrear'], ceil($source_data_array[
'bitsvolume']/8),
false);
638 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'volumechange'][
'leftrear'], ceil($source_data_array[
'bitsvolume']/8),
false);
639 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'peakvolume'][
'rightrear'], ceil($source_data_array[
'bitsvolume']/8),
false);
640 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'peakvolume'][
'leftrear'], ceil($source_data_array[
'bitsvolume']/8),
false);
641 }
642 if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] ||
643 $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
644 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'volumechange'][
'center'], ceil($source_data_array[
'bitsvolume']/8),
false);
645 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'peakvolume'][
'center'], ceil($source_data_array[
'bitsvolume']/8),
false);
646 }
647 if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
648 $framedata .=
getid3_lib::BigEndian2String($source_data_array[
'volumechange'][
'bass'], ceil($source_data_array[
'bitsvolume']/8),
false);
650 }
651 }
652 break;
653
654 case 'EQU2':
655
656
657
658
659
660
661
662
663 if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1)) {
664 $this->errors[] = 'Invalid Interpolation Method byte in '.$frame_name.' ('.$source_data_array['interpolationmethod'].') (valid = 0 or 1)';
665 } else {
666 $framedata .= chr($source_data_array['interpolationmethod']);
667 $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00";
668 foreach ($source_data_array[
'data'] as
$key => $val) {
671 }
672 }
673 break;
674
675 case 'EQUA':
676
677
678
679
680
681
682
683
685 $this->errors[] = 'Invalid Adjustment Bits byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)';
686 } else {
687 $framedata .= chr($source_data_array['adjustmentbits']);
688 foreach ($source_data_array as
$key => $val) {
689 if (
$key !=
'bitsvolume') {
691 $this->errors[] =
'Invalid Frequency in '.$frame_name.
' ('.
$key.
') (range = 0 to 32767)';
692 } else {
693 if ($val >= 0) {
694
696 }
699 }
700 }
701 }
702 }
703 break;
704
705 case 'RVRB':
706
707
708
709
710
711
712
713
714
715
716
718 $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['left'].') (range = 0 to 65535)';
719 } elseif (!$this->
IsWithinBitRange($source_data_array[
'right'], 16,
false)) {
720 $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['right'].') (range = 0 to 65535)';
721 } elseif (!$this->
IsWithinBitRange($source_data_array[
'bouncesL'], 8,
false)) {
722 $this->errors[] = 'Invalid Reverb Bounces, Left in '.$frame_name.' ('.$source_data_array['bouncesL'].') (range = 0 to 255)';
723 } elseif (!$this->
IsWithinBitRange($source_data_array[
'bouncesR'], 8,
false)) {
724 $this->errors[] = 'Invalid Reverb Bounces, Right in '.$frame_name.' ('.$source_data_array['bouncesR'].') (range = 0 to 255)';
725 } elseif (!$this->
IsWithinBitRange($source_data_array[
'feedbackLL'], 8,
false)) {
726 $this->errors[] = 'Invalid Reverb Feedback, Left-To-Left in '.$frame_name.' ('.$source_data_array['feedbackLL'].') (range = 0 to 255)';
727 } elseif (!$this->
IsWithinBitRange($source_data_array[
'feedbackLR'], 8,
false)) {
728 $this->errors[] = 'Invalid Reverb Feedback, Left-To-Right in '.$frame_name.' ('.$source_data_array['feedbackLR'].') (range = 0 to 255)';
729 } elseif (!$this->
IsWithinBitRange($source_data_array[
'feedbackRR'], 8,
false)) {
730 $this->errors[] = 'Invalid Reverb Feedback, Right-To-Right in '.$frame_name.' ('.$source_data_array['feedbackRR'].') (range = 0 to 255)';
731 } elseif (!$this->
IsWithinBitRange($source_data_array[
'feedbackRL'], 8,
false)) {
732 $this->errors[] = 'Invalid Reverb Feedback, Right-To-Left in '.$frame_name.' ('.$source_data_array['feedbackRL'].') (range = 0 to 255)';
733 } elseif (!$this->
IsWithinBitRange($source_data_array[
'premixLR'], 8,
false)) {
734 $this->errors[] = 'Invalid Premix, Left-To-Right in '.$frame_name.' ('.$source_data_array['premixLR'].') (range = 0 to 255)';
735 } elseif (!$this->
IsWithinBitRange($source_data_array[
'premixRL'], 8,
false)) {
736 $this->errors[] = 'Invalid Premix, Right-To-Left in '.$frame_name.' ('.$source_data_array['premixRL'].') (range = 0 to 255)';
737 } else {
740 $framedata .= chr($source_data_array['bouncesL']);
741 $framedata .= chr($source_data_array['bouncesR']);
742 $framedata .= chr($source_data_array['feedbackLL']);
743 $framedata .= chr($source_data_array['feedbackLR']);
744 $framedata .= chr($source_data_array['feedbackRR']);
745 $framedata .= chr($source_data_array['feedbackRL']);
746 $framedata .= chr($source_data_array['premixLR']);
747 $framedata .= chr($source_data_array['premixRL']);
748 }
749 break;
750
751 case 'APIC':
752
753
754
755
756
757
760 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
762 $this->errors[] =
'Invalid Picture Type byte in '.$frame_name.
' ('.$source_data_array[
'picturetypeid'].
') for ID3v2.'.
$this->majorversion;
764 $this->errors[] =
'Invalid MIME Type in '.$frame_name.
' ('.$source_data_array[
'mime'].
') for ID3v2.'.
$this->majorversion;
765 } elseif (($source_data_array[
'mime'] ==
'-->') && (!$this->
IsValidURL($source_data_array[
'data'],
false,
false))) {
766
767
768 $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
769 } else {
770 $framedata .= chr($source_data_array['encodingid']);
771 $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00";
772 $framedata .= chr($source_data_array['picturetypeid']);
774 $framedata .= $source_data_array['data'];
775 }
776 break;
777
778 case 'GEOB':
779
780
781
782
783
784
787 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
789 $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')';
790 } elseif (!$source_data_array['description']) {
791 $this->errors[] = 'Missing Description in '.$frame_name;
792 } else {
793 $framedata .= chr($source_data_array['encodingid']);
794 $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00";
795 $framedata .= $source_data_array['filename'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
796 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
797 $framedata .= $source_data_array['data'];
798 }
799 break;
800
801 case 'PCNT':
802
803
804
805
807 break;
808
809 case 'POPM':
810
811
812
813
814
815
817 $this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)';
818 } elseif (!$this->
IsValidEmail($source_data_array[
'email'])) {
819 $this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')';
820 } else {
821 $framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00";
822 $framedata .= chr($source_data_array['rating']);
824 }
825 break;
826
827 case 'RBUF':
828
829
830
831
832 if (!$this->
IsWithinBitRange($source_data_array[
'buffersize'], 24,
false)) {
833 $this->errors[] = 'Invalid Buffer Size in '.$frame_name;
834 } elseif (!$this->
IsWithinBitRange($source_data_array[
'nexttagoffset'], 32,
false)) {
835 $this->errors[] = 'Invalid Offset To Next Tag in '.$frame_name;
836 } else {
838 $flag .= '0000000';
839 $flag .= $source_data_array['flags']['embededinfo'] ? '1' : '0';
840 $framedata .= chr(bindec($flag));
842 }
843 break;
844
845 case 'AENC':
846
847
848
849
850
851 if (!$this->
IsWithinBitRange($source_data_array[
'previewstart'], 16,
false)) {
852 $this->errors[] = 'Invalid Preview Start in '.$frame_name.' ('.$source_data_array['previewstart'].')';
853 } elseif (!$this->
IsWithinBitRange($source_data_array[
'previewlength'], 16,
false)) {
854 $this->errors[] = 'Invalid Preview Length in '.$frame_name.' ('.$source_data_array['previewlength'].')';
855 } else {
856 $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
859 $framedata .= $source_data_array['encryptioninfo'];
860 }
861 break;
862
863 case 'LINK':
864
865
866
867
869 $this->errors[] = 'Invalid Frame Identifier in '.$frame_name.' ('.$source_data_array['frameid'].')';
870 } elseif (!$this->
IsValidURL($source_data_array[
'data'],
true,
false)) {
871
872
873 $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
874 } elseif ((($source_data_array['frameid'] == 'AENC') || ($source_data_array['frameid'] == 'APIC') || ($source_data_array['frameid'] == 'GEOB') || ($source_data_array['frameid'] == 'TXXX')) && ($source_data_array['additionaldata'] == '')) {
875 $this->errors[] = 'Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
876 } elseif (($source_data_array[
'frameid'] ==
'USER') && (
getid3_id3v2::LanguageLookup($source_data_array[
'additionaldata'],
true) ==
'')) {
877 $this->errors[] = 'Language must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
878 } elseif (($source_data_array['frameid'] == 'PRIV') && ($source_data_array['additionaldata'] == '')) {
879 $this->errors[] = 'Owner Identifier must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
880 } elseif ((($source_data_array[
'frameid'] ==
'COMM') || ($source_data_array[
'frameid'] ==
'SYLT') || ($source_data_array[
'frameid'] ==
'USLT')) && ((
getid3_id3v2::LanguageLookup(substr($source_data_array[
'additionaldata'], 0, 3),
true) ==
'') || (substr($source_data_array[
'additionaldata'], 3) ==
''))) {
881 $this->errors[] = 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
882 } else {
883 $framedata .= $source_data_array['frameid'];
884 $framedata .= str_replace("\x00", '', $source_data_array['data'])."\x00";
885 switch ($source_data_array['frameid']) {
886 case 'COMM':
887 case 'SYLT':
888 case 'USLT':
889 case 'PRIV':
890 case 'USER':
891 case 'AENC':
892 case 'APIC':
893 case 'GEOB':
894 case 'TXXX':
895 $framedata .= $source_data_array['additionaldata'];
896 break;
897 case 'ASPI':
898 case 'ETCO':
899 case 'EQU2':
900 case 'MCID':
901 case 'MLLT':
902 case 'OWNE':
903 case 'RVA2':
904 case 'RVRB':
905 case 'SYTC':
906 case 'IPLS':
907 case 'RVAD':
908 case 'EQUA':
909
910 break;
911 case 'RBUF':
912 if ($this->majorversion == 3) {
913
914 } else {
915 $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')';
916 }
917
918 default:
919 if ((substr($source_data_array['frameid'], 0, 1) == 'T') || (substr($source_data_array['frameid'], 0, 1) == 'W')) {
920
921 } else {
922 $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')';
923 }
924 break;
925 }
926 }
927 break;
928
929 case 'POSS':
930
931
932
933 if (($source_data_array['timestampformat'] < 1) || ($source_data_array['timestampformat'] > 2)) {
934 $this->errors[] = 'Invalid Time Stamp Format in '.$frame_name.' ('.$source_data_array['timestampformat'].') (valid = 1 or 2)';
935 } elseif (!$this->
IsWithinBitRange($source_data_array[
'position'], 32,
false)) {
936 $this->errors[] = 'Invalid Position in '.$frame_name.' ('.$source_data_array['position'].') (range = 0 to 4294967295)';
937 } else {
938 $framedata .= chr($source_data_array['timestampformat']);
940 }
941 break;
942
943 case 'USER':
944
945
946
947
950 $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')';
952 $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
953 } else {
954 $framedata .= chr($source_data_array['encodingid']);
955 $framedata .= strtolower($source_data_array['language']);
956 $framedata .= $source_data_array['data'];
957 }
958 break;
959
960 case 'OWNE':
961
962
963
964
965
968 $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')';
969 } elseif (!$this->IsANumber($source_data_array['pricepaid']['value'], false)) {
970 $this->errors[] = 'Invalid Price Paid in '.$frame_name.' ('.$source_data_array['pricepaid']['value'].')';
971 } elseif (!$this->IsValidDateStampString($source_data_array['purchasedate'])) {
972 $this->errors[] = 'Invalid Date Of Purchase in '.$frame_name.' ('.$source_data_array['purchasedate'].') (format = YYYYMMDD)';
973 } else {
974 $framedata .= chr($source_data_array['encodingid']);
975 $framedata .= str_replace("\x00", '', $source_data_array['pricepaid']['value'])."\x00";
976 $framedata .= $source_data_array['purchasedate'];
977 $framedata .= $source_data_array['seller'];
978 }
979 break;
980
981 case 'COMR':
982
983
984
985
986
987
988
989
990
991
994 $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')';
995 } elseif (!$this->IsValidDateStampString($source_data_array['pricevaliduntil'])) {
996 $this->errors[] = 'Invalid Valid Until date in '.$frame_name.' ('.$source_data_array['pricevaliduntil'].') (format = YYYYMMDD)';
997 } elseif (!$this->
IsValidURL($source_data_array[
'contacturl'],
false,
true)) {
998 $this->errors[] = 'Invalid Contact URL in '.$frame_name.' ('.$source_data_array['contacturl'].') (allowed schemes: http, https, ftp, mailto)';
1000 $this->errors[] = 'Invalid Received As byte in '.$frame_name.' ('.$source_data_array['contacturl'].') (range = 0 to 8)';
1002 $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')';
1003 } else {
1004 $framedata .= chr($source_data_array['encodingid']);
1005 unset($pricestring);
1006 foreach ($source_data_array[
'price'] as
$key => $val) {
1008 $pricestrings[] =
$key.$val[
'value'];
1009 } else {
1010 $this->errors[] =
'Invalid Price String in '.$frame_name.
' ('.
$key.$val[
'value'].
')';
1011 }
1012 }
1013 $framedata .= implode('/', $pricestrings);
1014 $framedata .= $source_data_array['pricevaliduntil'];
1015 $framedata .= str_replace("\x00", '', $source_data_array['contacturl'])."\x00";
1016 $framedata .= chr($source_data_array['receivedasid']);
1017 $framedata .= $source_data_array['sellername'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
1018 $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
1019 $framedata .= $source_data_array['mime']."\x00";
1020 $framedata .= $source_data_array['logo'];
1021 }
1022 break;
1023
1024 case 'ENCR':
1025
1026
1027
1028
1029 if (!$this->
IsWithinBitRange($source_data_array[
'methodsymbol'], 8,
false)) {
1030 $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['methodsymbol'].') (range = 0 to 255)';
1031 } else {
1032 $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
1033 $framedata .= ord($source_data_array['methodsymbol']);
1034 $framedata .= $source_data_array['data'];
1035 }
1036 break;
1037
1038 case 'GRID':
1039
1040
1041
1042
1043 if (!$this->
IsWithinBitRange($source_data_array[
'groupsymbol'], 8,
false)) {
1044 $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)';
1045 } else {
1046 $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
1047 $framedata .= ord($source_data_array['groupsymbol']);
1048 $framedata .= $source_data_array['data'];
1049 }
1050 break;
1051
1052 case 'PRIV':
1053
1054
1055
1056 $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
1057 $framedata .= $source_data_array['data'];
1058 break;
1059
1060 case 'SIGN':
1061
1062
1063
1064 if (!$this->
IsWithinBitRange($source_data_array[
'groupsymbol'], 8,
false)) {
1065 $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)';
1066 } else {
1067 $framedata .= ord($source_data_array['groupsymbol']);
1068 $framedata .= $source_data_array['data'];
1069 }
1070 break;
1071
1072 case 'SEEK':
1073
1074
1076 $this->errors[] = 'Invalid Minimum Offset in '.$frame_name.' ('.$source_data_array['data'].') (range = 0 to 4294967295)';
1077 } else {
1079 }
1080 break;
1081
1082 case 'ASPI':
1083
1084
1085
1086
1087
1088
1089
1090 if (!$this->
IsWithinBitRange($source_data_array[
'datastart'], 32,
false)) {
1091 $this->errors[] = 'Invalid Indexed Data Start in '.$frame_name.' ('.$source_data_array['datastart'].') (range = 0 to 4294967295)';
1092 } elseif (!$this->
IsWithinBitRange($source_data_array[
'datalength'], 32,
false)) {
1093 $this->errors[] = 'Invalid Indexed Data Length in '.$frame_name.' ('.$source_data_array['datalength'].') (range = 0 to 4294967295)';
1094 } elseif (!$this->
IsWithinBitRange($source_data_array[
'indexpoints'], 16,
false)) {
1095 $this->errors[] = 'Invalid Number Of Index Points in '.$frame_name.' ('.$source_data_array['indexpoints'].') (range = 0 to 65535)';
1096 } elseif (!$this->
IsWithinBitRange($source_data_array[
'bitsperpoint'], 8,
false)) {
1097 $this->errors[] = 'Invalid Bits Per Index Point in '.$frame_name.' ('.$source_data_array['bitsperpoint'].') (range = 0 to 255)';
1098 } elseif ($source_data_array['indexpoints'] != count($source_data_array['indexes'])) {
1099 $this->errors[] = 'Number Of Index Points does not match actual supplied data in '.$frame_name;
1100 } else {
1105 foreach ($source_data_array[
'indexes'] as
$key => $val) {
1107 }
1108 }
1109 break;
1110
1111 case 'RGAD':
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 if (($source_data_array['track_adjustment'] > 51) || ($source_data_array['track_adjustment'] < -51)) {
1123 $this->errors[] = 'Invalid Track Adjustment in '.$frame_name.' ('.$source_data_array['track_adjustment'].') (range = -51.0 to +51.0)';
1124 } elseif (($source_data_array['album_adjustment'] > 51) || ($source_data_array['album_adjustment'] < -51)) {
1125 $this->errors[] = 'Invalid Album Adjustment in '.$frame_name.' ('.$source_data_array['album_adjustment'].') (range = -51.0 to +51.0)';
1127 $this->errors[] = 'Invalid Track Name Code in '.$frame_name.' ('.$source_data_array['raw']['track_name'].') (range = 0 to 2)';
1129 $this->errors[] = 'Invalid Album Name Code in '.$frame_name.' ('.$source_data_array['raw']['album_name'].') (range = 0 to 2)';
1131 $this->errors[] = 'Invalid Track Originator Code in '.$frame_name.' ('.$source_data_array['raw']['track_originator'].') (range = 0 to 3)';
1133 $this->errors[] = 'Invalid Album Originator Code in '.$frame_name.' ('.$source_data_array['raw']['album_originator'].') (range = 0 to 3)';
1134 } else {
1136 $framedata .=
getid3_lib::RGADgainString($source_data_array[
'raw'][
'track_name'], $source_data_array[
'raw'][
'track_originator'], $source_data_array[
'track_adjustment']);
1137 $framedata .=
getid3_lib::RGADgainString($source_data_array[
'raw'][
'album_name'], $source_data_array[
'raw'][
'album_originator'], $source_data_array[
'album_adjustment']);
1138 }
1139 break;
1140
1141 default:
1142 if ((($this->majorversion == 2) && (strlen($frame_name) != 3)) || (($this->majorversion > 2) && (strlen($frame_name) != 4))) {
1144 } elseif ($frame_name{0} == 'T') {
1145
1146
1147
1150 $this->errors[] =
'Invalid Text Encoding in '.$frame_name.
' ('.$source_data_array[
'encodingid'].
') for ID3v2.'.
$this->majorversion;
1151 } else {
1152 $framedata .= chr($source_data_array['encodingid']);
1153 $framedata .= $source_data_array['data'];
1154 }
1155 } elseif ($frame_name{0} == 'W') {
1156
1157
1158 if (!$this->
IsValidURL($source_data_array[
'data'],
false,
false)) {
1159
1160
1161 $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
1162 } else {
1163 $framedata .= $source_data_array['data'];
1164 }
1165 } else {
1166 $this->errors[] = $frame_name.' not yet supported in $this->GenerateID3v2FrameData()';
1167 }
1168 break;
1169 }
1170 }
1171 if (!empty($this->errors)) {
1172 return false;
1173 }
1174 return $framedata;
1175 }
static IsValidID3v2FrameName($framename, $id3v2majorversion)
static TextEncodingTerminatorLookup($encoding)
static LanguageLookup($languagecode, $casesensitive=false)
static RGADgainString($namecode, $originatorcode, $replaygain)
static Float2String($floatvalue, $bits)
static BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false)
ID3v2IsValidTextEncoding($textencodingbyte)
static ID3v2IsValidRGADname($RGADname)
ID3v2IsValidSYLTtype($contenttype)
static IsValidEmail($email)
ID3v2IsValidETCOevent($eventid)
static IsWithinBitRange($number, $maxbits, $signed=false)
static ID3v2IsValidRGADoriginator($RGADoriginator)
ID3v2IsValidCOMRreceivedAs($receivedas)
ID3v2IsValidPriceString($pricestring)
ID3v2IsValidAPICpicturetype($picturetype)
static IsValidURL($url, $allowUserPass=false)
static IsValidMIMEstring($mimestring)
$id3v2_default_encodingid
ID3v2IsValidAPICimageformat($imageformat)