english

learn php

learn css

learn html

learn javascript

learn php

8. regular expressions

solution 8.2
8 minutes / 1495 words

eight / solution 8.2

<?php

function initializeBook(string $tz = "America/Vancouver")
{
    global $fields, $book;
    !isset($fields) && ($fields = ["name", "nickname", "pronouns", "birthdate", "address", "email", "phone", "url", "socials", "created", "updated", "notes"]);
    !isset($book) && ($book = []);
    date_default_timezone_set($tz);
}

function newEntry(string $name = "anonymous")
{
    global $book;
    $id = uniqid("", true);
    return ($book[$id] = ["name" => $name, "created" => time(), "updated" => time()]) ? $id : false;
}

function updateEntryStamp(string $e)
{
    global $book;
    return entryExists($e) && ($book[$e]["updated"] = time());
}

function entryExists(string $e)
{
    global $book;
    return isset($book[$e]);
}

function checkFieldArray(string $e, string $f)
{
    global $book;
    if (!entryExists($e)) {
        return false;
    }
    !isset($book[$e][$f]) && ($book[$e][$f] = []);
    return true;
}

function setKeyValue(string $e, string $type, string $k, string $v)
{
    // sets values in multiple-value elements
    global $book;
    return entryExists($e) && checkFieldArray($e, $type) && ($book[$e][$type][$k] = trim($v)) && updateEntryStamp($e);
}

function setValue(string $e, string $type, string $v)
{
    // sets values in single-value elements
    global $book;
    return entryExists($e) && ($book[$e][$type] = $v) && updateEntryStamp($e);
}

function addNickname(string $e, string $v)
{
    // nicknames are the one exception where multiple values are possible but have no named keys so there's no point in writing a meta-function to deal with only one type
    global $book;
    return entryExists($e) && checkFieldArray($e, "nickname") && !in_array(trim($v), $book[$e]["nickname"]) && ($book[$e]["nickname"][] = trim($v)) && updateEntryStamp($e);
}
function setBirthdate(string $e, int $v)
{
    setValue($e, "birthdate", $v);
}
function setPronouns(string $e, string $v)
{
    setValue($e, "pronouns", $v);
}
function setNotes(string $e, string $v)
{
    setValue($e, "notes", $v);
}
function setAddress(string $e, string $k, string $v)
{
    return setKeyValue($e, "address", $k, $v);
}
function setEmail(string $e, string $k, string $v)
{
    return setKeyValue($e, "email", $k, $v);
}
function setPhone(string $e, string $k, string $v)
{
    return setKeyValue($e, "phone", $k, $v);
}
function setUrl(string $e, string $k, string $v)
{
    return setKeyValue($e, "url", $k, $v);
}
function setSocials(string $e, string $k, string $v)
{
    return setKeyValue($e, "socials", $k, $v);
}

function lower(string $i)
{
    return mb_convert_case($i, MB_CASE_LOWER);
}
function upper(string $i)
{
    return mb_convert_case($i, MB_CASE_UPPER);
}
function title(string $i)
{
    return mb_convert_case($i, MB_CASE_TITLE);
}

function cleanEntries()
{
    global $book, $fields;
    foreach ($book as &$entry) {
        foreach ($fields as $field) {
            if (isset($entry[$field])) {
                $i = &$entry[$field];
                if ($field == "name" || $field == "pronouns" || $field == "notes") {
                    $i = trim($i);
                    $field == "name" && ($i = title($i));
                    $field == "pronouns" && ($i = lower($i));
                }
                if ($field == "nickname" || $field == "address" || $field == "email" || $field == "phone" || $field == "url" || $field == "socials") {
                    $i = array_change_key_case($i, CASE_LOWER);
                    foreach ($i as &$v) {
                        $v = trim($v);
                    }
                    if ($field == "nickname") {
                        foreach ($i as &$v) {
                            $v = lower($v);
                        }
                    }
                    if ($field == "address") {
                        foreach ($i as &$v) {
                            $v = title($v);
                        }
                    }
                    if ($field == "email") {
                        foreach ($i as &$v) {
                            $v = lower($v);
                            $v = str_replace([" ", "\t", "\n"], "", $v);
                        }
                    }
                }
            }
        }
    }
}

function searchBook(string $s = "")
{
    global $book;

    $s = trim($s);
    if (!$s) {
        $results = $book;
    } else {
        $results = [];
        foreach ($book as $entry) {
            str_contains(lower($entry["name"]), lower($s)) && ($results[] = $entry);
        }
    }

    if (!count($results)) {
        print_r("sorry, nobody with that name was found.\n");
        return;
    }

    count($results) == 1 ? showEntry($results) : showEntries($results);
}

function showEntry(array $entry)
{
    $entry = $entry[0];

    print_r($entry["name"]);
    isset($entry["pronouns"]) && print_r(" (" . $entry["pronouns"] . ")");
    isset($entry["nickname"]) && print_r(" (" . implode(", ", $entry["nickname"]) . ")");
    print_r("\n");

    isset($entry["birthdate"]) && print_r("born " . date("F d, Y", $entry["birthdate"]) . "\n");

    foreach (["address", "email", "phone", "url", "socials"] as $f) {
        if (isset($entry[$f]) && count($entry[$f])) {
            foreach ($entry[$f] as $k => $v) {
                print_r("\n" . $k . "\n" . $v . "\n");
            }
        }
    }

    isset($entry["notes"]) && print_r("\nnotes\n\n" . $entry["notes"] . "\n");

    print_r("\n");

    foreach (["created", "updated"] as $k) {
        isset($entry[$k]) && print_r($k . " " . date("Y.m.d h.i.s", $entry[$k]) . "\n");
    }
}

function showEntries(array $results)
{
    global $fields;
    foreach ($fields as $field) {
        print_r($field . "\t");
    }
    print_r("\n");

    foreach ($results as $entry) {
        foreach ($fields as $field) {
            if (isset($entry[$field])) {
                $i = $entry[$field];
                ($field == "name" || $field == "pronouns" || $field == "notes") && print_r(str_replace("\n", ", ", $i));
                $field == "birthdate" && print_r(date("Y.m.d", $i));
                ($field == "created" || $field == "updated") && print_r(date("Y.m.d h.i.s", $i));
                $field == "nickname" && print_r(implode(", ", $i));
                if ($field == "address" || $field == "email" || $field == "phone" || $field == "url" || $field == "socials") {
                    $build = [];
                    foreach ($i as $k => $v) {
                        $build[] = $k . " - " . str_replace("\n", ", ", $v);
                    }
                    print_r(implode(", ", $build));
                }
            }
            print_r("\t"); // after each element
        }
        print_r("\n"); // after each entry
    }
}

function verifyEmail(string $e)
{
    // check for basic pattern ([email protected])
    if (!preg_match("/.+@.+\..+/", $e)) {
        return false;
    }

    // convert to lowercase
    $e = mb_convert_case($e, MB_CASE_LOWER);

    // eliminate whitespace
    $e = preg_replace("/\s+/", "", $e);

    // simplify consecutive periods
    $e = preg_replace("/\.+/", ".", $e);

    // split email into name and domain because their constraints are different
    $name = explode("@", $e)[0];
    $domain = explode("@", $e)[1];

    // check for both elements
    if (!strlen($name) || !strlen($domain)) {
        return false;
    }

    // remove leading/trailing periods
    $name = trim($name, ".");
    $domain = trim($domain, ".");

    // remove invalid characters from both sections
    $name = preg_replace("/[^a-z0-9!#%\$&\'\*\+\-\/\=\?\^_`\{|\}~\.]/", "", $name);
    $domain = preg_replace("/[^a-z0-9\-\.]/", "", $domain);

    // crop name to 64 characters
    $name = substr($name, 0, 64);

    // crop each domain segment to 63 characters
    $domain = explode(".", $domain);
    foreach ($domain as &$i) {
        $i = substr($i, 0, 63);
    }
    $domain = implode(".", $domain);

    // check for both elements again (in case all characters were invalid)
    if (!strlen($name) || !strlen($domain)) {
        return false;
    }

    // rebuild email
    $e = $name . "@" . $domain;

    return $e;
}

function verifyBookEmails()
{
    global $book;
    foreach ($book as &$entry) {
        if (isset($entry["email"]) && count($entry["email"])) {
            foreach ($entry["email"] as $k => &$i) {
                $originalEmail = $i;
                $newEmail = verifyEmail($i);
                if (!$newEmail) {
                    print_r("invalid email \"" . $originalEmail . "\" for " . $entry["name"] . " removed\n");
                    unset($entry["email"][$k]);
                    continue;
                }
                $originalEmail != $newEmail && ($i = $newEmail);
            }
        }
    }
}

initializeBook();

// Sharon Wu
$e = newEntry("Sharon Wu");
setPronouns($e, "she/they");
addNickname($e, "woozie");
addNickname($e, "shar");
setBirthdate($e, 654359400);
setAddress($e, "home", "126 Main Street\nPhiladelphia, PA 19127\nUnited States of America");
setEmail($e, "work", "sharon@.....");
setPhone($e, "work", "+1.234.567.8901");
setUrl($e, "work", "https://php.org/sharon.wu");
setSocials($e, "instagram", "@php.sharon.wu");

// Lori Kim
$e = newEntry("Lori Kim");
setPronouns($e, "she/her");
addNickname($e, "lor");
addNickname($e, "pookie");
setBirthdate($e, 774196200);
setEmail($e, "work", "[email protected]");
setPhone($e, "work", "+1.234.567.8901");
setUrl($e, "work", "https://php.org/lori.kim");
setSocials($e, "instagram", "@php.lori.kim");

// Disha Wish
$e = newEntry("Disha Wish");
setPronouns($e, "she/they");
addNickname($e, "star");
setBirthdate($e, 866471400);
setEmail($e, "work", "[email protected]");
setEmail($e, "home", "[email protected]");
setPhone($e, "work", "+1.234.567.8901");
setUrl($e, "work", "https://php.org/disha.wish");
setSocials($e, "instagram", "@php.disha.wish");

// Emily Barnes
$e = newEntry("Emily Barnes");
setPronouns($e, "they/them");
addNickname($e, "adoorable");
addNickname($e, "stable");
setBirthdate($e, 1075476600);
setAddress($e, "home", "6200 University Boulevard\nVancouver, BC V6T 1Z4\nCanada");
setEmail($e, "work", "[email protected]");
setEmail($e, "home", "[email protected]");
setPhone($e, "work", "+1.234.567.8901");
setUrl($e, "work", "https://php.org/emily.barnes");
setSocials($e, "instagram", "@php.emily.barnes");

// Evelyn Silk
$e = newEntry("Evelyn Silk");
setPronouns($e, "they/she");
addNickname($e, "smoothie");
addNickname($e, "eve");
setBirthdate($e, 630516600);
setAddress($e, "home", "1 rue Victor Cousin\n75005 Paris\nFrance");
setEmail($e, "work", "[email protected]");
setEmail($e, "home", "[email protected]");
setPhone($e, "work", "+33.234.567.8901");
setUrl($e, "work", "https://php.org/evelyn.silk");
setSocials($e, "instagram", "@php.evelyn.silk");

// Ava Machs
$e = newEntry("Ava Machs");
setPronouns($e, "she/they");
addNickname($e, "pads");
setBirthdate($e, 600535800);
setAddress($e, "home", "99 Shangda Road\nBaoshan District, Shanghai 200444\nChina");
setEmail($e, "work", "[email protected]");
setEmail($e, "home", "[email protected]");
setPhone($e, "work", "+86.234.567.8901");
setUrl($e, "work", "https://php.org/ava.machs");
setSocials($e, "instagram", "@php.ava.machs");

// Harper Wren
$e = newEntry("Harper Wren");
setPronouns($e, "they/them");
addNickname($e, "wrinkle");
addNickname($e, "birdie");
setBirthdate($e, 946567800);
setAddress($e, "home", "80 Wellington Street\nOttawa, ON K1A 0A2\nCanada");
setEmail($e, "work", "[email protected]");
setEmail($e, "home", "[email protected]");
setPhone($e, "work", "+1.234.567.8901");
setUrl($e, "work", "https://php.org/harper.wren");
setSocials($e, "instagram", "@php.harper.wren");

// Mia Lynx
$e = newEntry("Mia Lynx");
setPronouns($e, "they/it");
addNickname($e, "furry");
setBirthdate($e, 1005147000);
setAddress($e, "home", "Nueva Tajamar 481\nTorre Norte, Las Condes, Santiago\nChile");
setEmail($e, "work", "[email protected]");
setEmail($e, "home", "[email protected]");
setPhone($e, "work", "+56.234.567.8901");
setUrl($e, "work", "https://php.org/mia.lynx");
setSocials($e, "instagram", "@php.mia.lynx");

// Sophie Koh
$e = newEntry("Sophie Koh");
setPronouns($e, "she/they");
addNickname($e, "kodiak");
setBirthdate($e, 1049470200);
setAddress($e, "home", "1 Zmora Street\nJerusalem, 9515701\nIsrael");
setEmail($e, "work", "[email protected]");
setPhone($e, "work", "+972.234.567.8901");
setUrl($e, "work", "https://php.org/sophie.koh");
setSocials($e, "instagram", "@php.sophie.koh");

// Harper Wren
$e = newEntry("Isla White");
setPronouns($e, "she/her");
addNickname($e, "scottie");
addNickname($e, "black");
setBirthdate($e, 1062426600);
setEmail($e, "work", "[email protected]");
setPhone($e, "work", "+1.234.567.8901");
setUrl($e, "work", "https://php.org/isla.white");
setSocials($e, "instagram", "@php.isla.white");

cleanEntries();
verifyBookEmails();
searchBook();

learn php

learn css

learn html

learn javascript

powered by akelei. an avi sato project.