github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/php/parse_pecl_pear.go (about) 1 package php 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/elliotchance/phpserialize" 9 10 "github.com/anchore/syft/internal/unknown" 11 "github.com/anchore/syft/syft/artifact" 12 "github.com/anchore/syft/syft/file" 13 "github.com/anchore/syft/syft/pkg" 14 "github.com/anchore/syft/syft/pkg/cataloger/generic" 15 ) 16 17 type peclPearData struct { 18 Name string 19 Channel string 20 Version string 21 License []string 22 } 23 24 func (p *peclPearData) ToPear() pkg.PhpPearEntry { 25 return pkg.PhpPearEntry{ 26 Name: p.Name, 27 Channel: p.Channel, 28 Version: p.Version, 29 License: p.License, 30 } 31 } 32 33 func (p *peclPearData) ToPecl() pkg.PhpPeclEntry { //nolint:staticcheck 34 return pkg.PhpPeclEntry(p.ToPear()) //nolint:staticcheck 35 } 36 37 func parsePecl(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 38 m, err := parsePeclPearSerialized(reader) 39 if err != nil { 40 return nil, nil, err 41 } 42 if m == nil { 43 return nil, nil, unknown.New(reader.Location, fmt.Errorf("no pecl package found")) 44 } 45 return []pkg.Package{newPeclPackage(ctx, *m, reader.Location)}, nil, nil 46 } 47 48 func parsePear(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 49 m, err := parsePeclPearSerialized(reader) 50 if err != nil { 51 return nil, nil, err 52 } 53 if m == nil { 54 return nil, nil, unknown.New(reader.Location, fmt.Errorf("no pear package found")) 55 } 56 return []pkg.Package{newPearPackage(ctx, *m, reader.Location)}, nil, nil 57 } 58 59 // parsePeclPearSerialized is a parser function for Pear metadata contents, returning "Default" php packages discovered. 60 func parsePeclPearSerialized(reader file.LocationReadCloser) (*peclPearData, error) { 61 data, err := io.ReadAll(reader) 62 63 if err != nil { 64 return nil, fmt.Errorf("failed to read file: %w", err) 65 } 66 67 metadata, err := phpserialize.UnmarshalAssociativeArray( 68 data, 69 ) 70 71 if err != nil { 72 return nil, fmt.Errorf("failed to parse pear metadata file: %w", err) 73 } 74 75 name, ok := metadata["name"].(string) 76 if !ok { 77 return nil, fmt.Errorf("failed to parse pear package name: %w", err) 78 } 79 80 channel, ok := metadata["channel"].(string) 81 if !ok { 82 // this could be the v5 format 83 channel = "" 84 } 85 86 version := readStruct(metadata, "version", "release") 87 license := readStruct(metadata, "license", "_content") 88 89 return &peclPearData{ 90 Name: name, 91 Channel: channel, 92 Version: version, 93 License: []string{ 94 license, 95 }, 96 }, nil 97 } 98 99 func readStruct(metadata any, fields ...string) string { 100 if len(fields) > 0 { 101 value, ok := metadata.(map[any]any) 102 if !ok { 103 return "" 104 } 105 return readStruct(value[fields[0]], fields[1:]...) 106 } 107 value, ok := metadata.(string) 108 if !ok { 109 return "" 110 } 111 return value 112 }