HEX
Server: Apache
System: Linux www3.pit.tblive.com 5.14.0-687.38.1.el9_8.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Aug 12 17:19:12 EDT 2026 x86_64
User: awaldron (1020)
PHP: 8.1.34
Disabled: exec,passthru,shell_exec,system
Upload Files
File: /home/awaldron/_domains/api.alanwaldron.com/v1/_globals.php
<?php

//**********************************************************************************************************//
// DATABASE FUNCTIONS **************************************************************************************//

function dbconnect() {
    // LOCALHOST
    if ($_SERVER['HTTP_HOST'] == 'localhost:8888') {
        $db = new mysqli('localhost', 'root', 'root', 'phcdc_members');
    }
    // PRODUCTION
    else if ($_SERVER['HTTP_HOST'] == 'api.alanwaldron.com') {
        $db = new mysqli('localhost', 'awaldron_campaign', 'E2v[M5zHP2L9', 'awaldron_campaign');
    }

    if ($db->connect_errno) {
        response( 500, ['success' => false, 'errors' => ['Error connecting to the database.']]);
    }
    return $db;
}


//**********************************************************************************************************//
// CORS FUNCTIONS ******************************************************************************************//

function cors() {

    // Allow from any origin
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
        // you want to allow, and if so:
        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Max-Age: 86400');    // cache for 1 day

    }

    // Access-Control headers are received during OPTIONS requests
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
            // may also be using PUT, PATCH, HEAD etc
            header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

        exit(0);
    }
}




//**********************************************************************************************************//
// API FUNCTIONS *******************************************************************************************//

function validate_body( $args, $rules ) {

    $valid = true;
    $errors = [];

    if ($args !== false && $rules !== false) {
        foreach ($rules as $param => $rule) {
            // CHECK REQUIRED
            if (strstr($rule,'req')) {
                if (empty($args[$param])) {
                    $valid = false;
                    $errors[] = $param.' is required.';
                }
            }
            // CHECK EMAIL
            if (strstr($rule,'email')) {
                if (!filter_var($args[$param], FILTER_VALIDATE_EMAIL)) {
                    $valid = false;
                    $errors[] = $param.' is not a valid email address.';
                }
            }
        }
    }

    if (!$valid) {
        response( 400, ['success'=>false,'errors'=>$errors]);
    }
    return true;
}

function validate_token( $uid ) {
    // IF uid==0 THEN THROW ERROR INVALID TOKEN
    if ($uid !== false && $uid === 0) {
        response( 401, ['success'=>false,'errors'=>['Security token invalid.'.$_SERVER['HTTP_AUTHORIZATION']]]);
    }
}

function validate_admin( $is_admin ) {
    // IF is_admin==0 THEN THROW ERROR NOT AUTHORIZED
    if (!$is_admin) {
        response( 401, ['success'=>false,'errors'=>['Unauthorized. User must be an admin.']]);
    }
}

function utf8ize($d) {
    if (is_array($d)) {
        foreach ($d as $k => $v) {
            $d[$k] = utf8ize($v);
        }
    } else if (is_string ($d)) {
        return utf8_encode($d);
    }
    return $d;
}


function response( $responseCode=200, $responseBody=[] ) {
    http_response_code($responseCode);
    header('Content-Type: application/json');
    echo json_encode(utf8ize($responseBody));
    exit;
}


function new_token( $db, $uid ) {
    $token = bin2hex(random_bytes(64));
    $created = time();
    $expires = time() + 60*60*12;
    $ins = "INSERT INTO tokens 
            (user_id, token, created, expires) VALUES 
            (".$uid.",'".$token."',".$created.",".$expires.")";
    if ($result = $db->query($ins)) {
        return [
            'token' => $token,
            'created' => $created,
            'expires' => $expires
        ];
    } else {
        response( 400, ['success'=>false,'errors'=>['Error creating token.']]);
    }
}

function check_token( $db, $token ) {
    $sql = "SELECT token_id, user_id FROM tokens WHERE token='".$token."' AND expires > ".time();
    $res = qRow( $db, $sql );
    if (!empty($res['user_id'])) {
        // UPDATE TOKEN EXPIRATION
        $upd = "UPDATE tokens SET expires=".(time()+60*60*12)." WHERE token_id=".$res['token_id'];
        $db->query($upd);
        return $res['user_id'];
    } else {
        return 0;
    }
}


function randomString($n) {
    $characters = '01234567890123456789ABCDEFGHIJKLMNPQRSTUVWXYZABCDEFGHIJKLMNPQRSTUVWXYZ';
    $randomString = '';

    for ($i = 0; $i < $n; $i++) {
        $index = rand(0, strlen($characters) - 1);
        $randomString .= $characters[$index];
    }

    return $randomString;
}

function randomPassword($n) {
    $uppers = "ABCDEFGHIJKLMNPQRSTUVWXYZABCDEFGHIJKLMNPQRSTUVWXYZ";
    $downers = "abcdefghijklmnpqrstuvwxyzabcdefghijklmnpqrstuvwxyz";
    $numbers = "01234567890123456789";
    $symbols = "!@#$%&*!@#$%&*";

    $randomString = '';

    // 1 Uppercase
    for ($i = 0; $i < 1; $i++) {
        $index = rand(0, strlen($uppers) - 1);
        $randomString .= $uppers[$index];
    }

    // 3 Lowercase
    for ($i = 0; $i < 3; $i++) {
        $index = rand(0, strlen($downers) - 1);
        $randomString .= $downers[$index];
    }

    // 4 Numbers
    for ($i = 0; $i < 4; $i++) {
        $index = rand(0, strlen($numbers) - 1);
        $randomString .= $numbers[$index];
    }

    // 1 symbols
    for ($i = 0; $i < 1; $i++) {
        $index = rand(0, strlen($symbols) - 1);
        $randomString .= $symbols[$index];
    }


    return $randomString;
}


//**********************************************************************************************************//
// DB HELPER FUNCTIONS *************************************************************************************//


function qVal( $db, $sql ) {
    $res = $db->query($sql);
    if ($res->num_rows > 0) {
        $row = $res->fetch_assoc();
        foreach ($row as $k => $v) {
            return $v;
        }
    } else {
        return false;
    }
}

function qRow( $db, $sql ) {
    $res = $db->query($sql);
    if ($res->num_rows > 0) {
        $row = $res->fetch_assoc();
        return $row;
    } else {
        return false;
    }
}

function qSet( $db, $sql ) {
    $out = [];
    $res = $db->query($sql);
    while ($row = $res->fetch_assoc()) {
        $out[] = $row;
    }
    return $out;
}

function qsql( $q ) {
    if ($q->num_rows() == 0) return false;
    else {
        $r = $q->result_array();
        $r = $r[0];
        foreach ($r as $k => $v) return $v;
    }
}

function qin( $a ) {
    $in = '(';
    for ($i=0; $i < count($a); $i++) {
        if ($i > 0) $in .= ',';
        $in .= "'".$a[$i]."'";
    }
    $in .= ')';
    return $in;
}

function shut(){

    $error = error_get_last();

    if($error && ($error['type'] & E_FATAL)){
        handler($error['type'], $error['message'], $error['file'], $error['line']);
    }

}

function handler( $errno, $errstr, $errfile, $errline ) {

    switch ($errno){

        case E_ERROR: // 1 //
            $typestr = 'E_ERROR'; break;
        case E_WARNING: // 2 //
            $typestr = 'E_WARNING'; break;
        case E_PARSE: // 4 //
            $typestr = 'E_PARSE'; break;
        case E_NOTICE: // 8 //
            $typestr = 'E_NOTICE'; break;
        case E_CORE_ERROR: // 16 //
            $typestr = 'E_CORE_ERROR'; break;
        case E_CORE_WARNING: // 32 //
            $typestr = 'E_CORE_WARNING'; break;
        case E_COMPILE_ERROR: // 64 //
            $typestr = 'E_COMPILE_ERROR'; break;
        case E_COMPILE_WARNING: // 128 //
            $typestr = 'E_COMPILE_WARNING'; break;
        case E_USER_ERROR: // 256 //
            $typestr = 'E_USER_ERROR'; break;
        case E_USER_WARNING: // 512 //
            $typestr = 'E_USER_WARNING'; break;
        case E_USER_NOTICE: // 1024 //
            $typestr = 'E_USER_NOTICE'; break;
        case E_STRICT: // 2048 //
            $typestr = 'E_STRICT'; break;
        case E_RECOVERABLE_ERROR: // 4096 //
            $typestr = 'E_RECOVERABLE_ERROR'; break;
        case E_DEPRECATED: // 8192 //
            $typestr = 'E_DEPRECATED'; break;
        case E_USER_DEPRECATED: // 16384 //
            $typestr = 'E_USER_DEPRECATED'; break;

    }

    $message = '<b>'.$typestr.': </b>'.$errstr.' in <b>'.$errfile.'</b> on line <b>'.$errline.'</b><br/>';

    if(($errno & E_FATAL) && ENV === 'production'){

        header('Location: 500.html');
        header('Status: 500 Internal Server Error');

    }

    if(!($errno & ERROR_REPORTING))
        return;

    if(DISPLAY_ERRORS) {
        response( 400, ['success'=>false,'error'=>$message]);
        //printf('%s', $message);
    }
    //Logging error on php file error log...
    if(LOG_ERRORS)
        error_log(strip_tags($message), 0);

}



function get_email_template( $user ) {
    $email = <<<END
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Alan Waldron for Penn Hills Council</title>
    <style>
        body { background: #EEEEEE; font-family: sans-serif; font-size: 15px; line-height: 1.4em; }
        .outer { max-width: 600px; margin: 30px auto; background: #FFFFFF; padding: 10px 20px; border: solid 1px #CCCCCC; }
        #logo img { max-width: 280px; display: block; margin: 0 auto 20px; }
        .image img { float:left; max-width: 100px; border-radius: 100px; margin-right: 14px; margin-bottom: 14px; }
        .nobreak { overflow: auto; }
        .centered { text-align: center; }
        a.btn { display:inline-block; padding: 15px 40px; border-radius: 8px; text-decoration: none; }
        a.btn.green { background: #009900; color: #FFFFFF; font-weight: bold; font-size: 24px; margin-right: 10px; }
        a.btn.red { background: #990000; color: #FFFFFF; font-weight: bold; font-size: 24px; }
    </style>
</head>
<body>
    <div class="outer">
    <p id="logo">
        <img src="https://api.alanwaldron.com/v1/mail/read1/[ID]" alt="" />

    </p>
    <hr/>
        <div class="nobreak">
        <p class="image">
            <img src="https://api.alanwaldron.com/alanwaldron.jpg" alt="" />
        </p>
        <p>Dear [NAME],</p>
        <p>My name is Alan Waldron and I am asking for your endorsement for a seat on the Penn Hills Municipal Council.</p>
        </div>
        <p><b>Fast Facts:</b></p>
        <ul>
            <li>Penn Hills resident since 2004</li>
            <li>Graduate of the University of Pittsburgh</li>
            <li>Website / Software developer of 25+ years</li>
            <li>6 years of marketing experience at <a href="https://pipitone.com" style="color:#950000;" target="_blank">Pipitone</a></li>
            <li>Partner at software agency <a href="https://buildinmotion.com" style="color:#950000;" target="_blank">Build in Motion</a></li>
            <li>Vice President of the <a href="https://pennhillscdc.org" style="color:#950000;" target="_blank">Penn Hills CDC</a></li>
        </ul>
        <p>Long-time Penn Hills residents often lament the fact that our community just isn't what it once was. I wasn't here in those days but by all accounts, it was a wonderful slice of Americana, so I can surely sympathize.</p>
        <p>However, as someone who has lived here for only 20 years, I think Penn Hills is pretty great. Sure we've lost some restaurants and businesses, but these problems aren't unique to Penn Hills and we still have a lot going on for us.</p>
        <p>In fact, I believe the only thing we had 40 years ago that we're missing today is a shared identity.</p>
        <p>Who are we? What do we stand for? Why do people live here and why should people want to live here?</p>
        <p>These are questions we've punted on for too long and that's just allowed those outside of our borders to answer them for us. We know what they think of us, and we also know how wrong they are.</p>
        <p>If elected to council, my focus will be on rehabilitating the image of Penn Hills not only to outsiders, but with our own residents.</p>
        <p>To that end, I've already begun working with the current mayor and council on ideas for a comprehensive marketing campaign aimed at getting people to think differently about Penn Hills.</p>
        <p>But even more importantly, council must build a strong working relationship with our school district to align our common goals and initiatives. The success of our municipality is directly linked to the success of our school district, and vice-versa. It is imperative that those in our government stop saying "that's a school district problem" for the sake political expediency. Like it or not, a school district problem is a municipal problem.</p>
        <p>If we are successful, we will attract new residents while retaining existing ones. And the resulting population growth will attract new businesses, services and amenities to Penn Hills which will, in turn, increase property values and make our community safer.</p>
        <p>If you believe in this vision as I do, then I ask that you endorse me for Penn Hills Council.</p>
        <p>Thank you for your time and consideration, and I look forward to seeing you at Tuesday's vote.</p>
        <p>All the best,<br/>Alan Waldron</p>
        <p>P.S. - If you have any questions please feel free to call or text me at <a href="tel:14124002934" style="color:#950000;">412-400-2934</a></p>
        <p>&nbsp;</p>

        <h2 class="centered">Can I count on your endorsement?</h2>
        <p class="centered">
            <a href="https://api.alanwaldron.com/v1/mail/log/[ID]/1" class="btn green">YES!</a>
            <a href="https://api.alanwaldron.com/v1/mail/log/[ID]/0" class="btn red">No</a>
        </p>
    </div>
</body>
</html>
END;

    $email = str_replace('[NAME]', $user['fname'], $email);
    $email = str_replace('[ID]', $user['id'], $email);

    return $email;
}