3
\$\begingroup\$

I am making a class in PHP that detects the social network or instant messaging platform of a given URL:

class SocialLinkParser
{
    const TELEGRAMM='telegramm';
    const WHATSUP='whatsup';

    const YOUTUBE='youtube';

    const INSTAGRAMM='instagram';
    const LINKEDIN='linkedin';
    const TWITTER='twitter';
    const FACEBOOK='facebook';

    const PINTEREST='pinterest';

    const REDDIT='reddit';

    const URL_MAPPINGS = [
        'tg'=>self::TELEGRAMM,
        't.me'=>self::TELEGRAMM,
        'wa.me'=>self::WHATSUP,
        'youtu.be'=>self::YOUTUBE,
        'instagr.am'=>self::INSTAGRAMM,
        'lnkd.in'=>self::LINKEDIN,
        't.co'=>self::TWITTER,
        'x.com'=>self::TWITTER,
        'fb.me'=>self::FACEBOOK,
        'pin.it'=>self::PINTEREST,
        'redd.it'=>self::REDDIT
    ];

    const SCHEME_MAPPINGS=[
        'tg'=>self::TELEGRAMM,
    ];

    public static function parse($link):string
    {
      
        $parsedLink = parse_url($link);
        $scheme = strtolower($parsedLink['scheme']);

        // Invitation links may not start with http
        if(!str_contains($scheme, 'http')){
            return self::SCHEME_MAPPINGS[$scheme]??$scheme;
        }

        $path = strtolower($parsedLink['path']);
        $domainParts = explode('.', $path);

        //remove last part. It is gtld
        array_pop($domainParts);

        return self::URL_MAPPINGS[$path]??trim(array_pop($domainParts));
    }
}

The idea is to detect the social network name for known socials depending the url format. I check both invitation links for whatup, telegramm, etc., and also known shortened urls that each network generates.

Somehow I want a mechanism that generates a specific value for each social network so I can decide later what Icon to render if render a list links into html. Thus making a unique string for each social helps me to have a map with available social Icons. The mechanism is implemented seperately in order to be flexible.


Edit1 Context

I am into a situation where I want to display these icons depending the social network of a URL (for example in a config social_icons.php):

<?php
return [
  'facebook'=> 'bi bi-facebook',
  'twitter'=> 'bi bi-twitter',
  'instagram'=> 'bi bi-instagram',
  'youtube'=> 'bi bi-youtube',
  'twitch'=>'bi bi-twitch',
  'telegram'=> 'bi bi-telegram',
  'viber'=> 'bi bi-viber',
  'skype'=> 'bi bi-skype',
  'reddit'=>'bi bi-reddit',
];

And for that I need to calculate the nessesary key for it. A usage example is:


$icons = require_once('icons.php');

$url = htmlspecialchars(($_POST['url']??""), ENT_QUOTES, 'UTF-8')
$icon = SocialLinkParser::parse($url)??"bi bi-link"

echo "<i class='$icon'></i> <a href=\"$url\">$url</a>";

I want to configure the nessesary icon into a seperate file so I approached it like this.

A possible input is:

  • IM invitation Links for example skype (skype:skype_username?call)
  • Http links for known services: http://instagram.com
\$\endgroup\$
1
  • \$\begingroup\$ telegramm and whatsup are improper spellings. This may not be a problem since they are associated constants, but this just hurts... \$\endgroup\$
    – STerliakov
    Commented Jun 27 at 15:21

1 Answer 1

5
\$\begingroup\$

test suite

The OP code doesn't have any unit tests, and it would benefit from some. It would help the Gentle Reader to better understand what URLs are in-scope and what kind are not.

specification

The code does not spell out a spec. In the Review Context we find a vague description about "detecting" a platform from a "given URL". I have to believe the Author had in mind some Generating Process that produces URLs suitable to present to parse() as input. That is, caller has an obligation to ensure an URL conforms to some spec before passing it in.

The OP doesn't offer much guidance about what that spec is. If we handed this code to a QA engineer and asked for tests, it's not clear what proper test code would look like.

comment vs. code

        // Invitation links may not start with http
        if(!str_contains($scheme, 'http')){

The comment describes one rule and the code implements a different rule.

Please have the code check the prefix of $scheme.

For that matter, scheme could be missing, which makes us generate
PHP Warning: Undefined array key "scheme"

design of Public API

This gets back to having a spec. The parse function doesn't spell out what it promises to return to caller. It has four return paths, and could offer values like

  • 'telegramm'
  • 'ftp'
  • ''
  • 'whatsup'
  • 'ac' (for 'https://www.cardiff.ac.uk/')

It's unclear what caller should do with a return value stemming from an empty lookup result, nor even how to recognize such a result. Please write a PhpDoc comment that describes what this function promises to do.

accidental match

    const URL_MAPPINGS = [
        'tg'=>self::TELEGRAMM,

The shortness of that key, and the absence of . dots, increase the chance of randomly matching unrelated URLs that have nothing to do with Telegramm. At least we're not doing substring match, which was my initial concern, given that many base64 strings contain that bi-gram.

Also, is this maybe copy-n-pasted from SCHEME_MAPPINGS, and it doesn't belong here at all?

vague comment

        //remove last part. It is gtld
        array_pop($domainParts);

Of the original seven gTLD's, I'm willing to believe that this code anticipates working with at least {.com, .net, .org}. The comment leaves it ambiguous whether domains like {.co, .mobi, .info} or more modern additions are contemplated.

Part of my concern relates to whether e.g. .co.uk is "top level" for parsing purposes, and whether stripping .uk would leave us with a misleading .co. A specification would help us to answer such questions.

It's unclear why trim()ing the result is important to caller, but certainly it does no harm.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.