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