public function LoadXML($xmlstr)
 {
     $this->cachedSecsLeft = 0;
     $this->cacheHit = false;
     try {
         $result = new SimpleXMLElement($xmlstr);
     } catch (Exception $e) {
         // malformed XML
         $this->Error = "malformed XML provided";
         return false;
     }
     $this->api = $result;
     if ($this->api->error) {
         $this->Error = (string) $this->api->error;
         return false;
     }
     $this->age = -get_timeLeft($this->api->currentTime);
     return $this->LoadAPI();
 }
function cache_api_retrieve($db, $apicall, $args = array(), $expiresOverride = 0)
{
    global $allApiCalls;
    if (!$db) {
        return null;
    }
    date_default_timezone_set("UTC");
    if ($expiresOverride != -1 || defined("API_DEBUG") && API_DEBUG != true) {
        // skip the cache, don't want to save it and won't be cached
        $key = hash('sha256', $apicall . implode($args));
        //$result = $link->query("SELECT expires, value FROM ".DB_PREFIX.CACHE_TABLE." WHERE apicall = '".$apicall."' AND keyv = '".$key."' LIMIT 1");
        $result = $db->selectWhere(CACHE_TABLE, ['apicall' => $apicall, 'keyv' => $key], ['expires', 'value']);
        if ($result != false) {
            if ($result->rows > 0) {
                // yay! got a cached value
                $row = $result->results[0];
                //echo "result: " .gzuncompress($row['value']);
                if (isset($allApiCalls)) {
                    $allApiCalls[] = array($apicall, $args, "cached");
                }
                return new CacheEntry(new SimpleXMLElement(gzuncompress($row['value']), LIBXML_NOCDATA), 1, get_timeLeft($row['expires']), $key, $apicall, $db);
            }
        }
    }
    // no cached value or it is old... have to do the query proper
    $req = curl_init(API_BASE_URL . $apicall);
    curl_setopt($req, CURLOPT_POST, true);
    curl_setopt($req, CURLOPT_PORT, 443);
    curl_setopt($req, CURLOPT_POSTFIELDS, $args);
    curl_setopt($req, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($req, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($req, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($req, CURLOPT_TIMEOUT, 30);
    curl_setopt($req, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
    //CA cert file
    $resp = curl_exec($req);
    $http_code = curl_getinfo($req, CURLINFO_HTTP_CODE);
    $http_errno = curl_errno($req);
    if (isset($allApiCalls)) {
        $allApiCalls[] = array($apicall, $args, "fetched");
    }
    curl_close($req);
    if ($http_errno == 60) {
        return new CacheEntry("Ssl is not working for Curl", null, null, null, null, $db);
    }
    if ($http_errno != 0) {
        return new CacheEntry($http_errno, null, null, null, null, $db);
    }
    if ($http_code != 200) {
        // major api failure
        return new CacheEntry("unexpected response code {$http_code}", null, null, null, null, $db);
    }
    try {
        $xml = new SimpleXMLElement($resp, LIBXML_NOCDATA);
    } catch (Exception $e) {
        // malformed XML
        return new CacheEntry("malformed XML document", null, null, null, null, $db);
    }
    if ($xml->error) {
        // error response, don't cache it...
        return new CacheEntry($xml, 0, null, null, null, $db);
    }
    if ($expiresOverride == -1) {
        // skip the cache, don't want to save it and won't be cached
        return new CacheEntry($xml, 0, null, null, null, $db);
    }
    $cachedUntil = (string) $xml->cachedUntil;
    if ($expiresOverride == 0) {
        // other overrides moved into specific files
        /* if ($apicall == "/char/MailMessages.xml.aspx") // only can get full msgs so often
           $cachedUntil = gmdate("Y-m-d H:i:s",time()+7*60*60);*/
    } else {
        $cachedUntil = gmdate("Y-m-d H:i:s", time() + $expiresOverride);
    }
    $db->insert(CACHE_TABLE, ["apicall" => $apicall, 'keyv' => $key, 'expires' => $cachedUntil, 'value' => gzcompress($resp, 6)]);
    return new CacheEntry($xml, 0, get_timeLeft($cachedUntil), $key, $apicall, $db);
}
function cache_api_retrieve($link, $apicall, $args = array(), $expiresOverride = 0)
{
    global $allApiCalls;
    if (!$link) {
        return null;
    }
    date_default_timezone_set("UTC");
    if ($expiresOverride != -1) {
        // skip the cache, don't want to save it and won't be cached
        global $_checkedTables;
        if (!$_checkedTables) {
            // create the table if it does not exist already otherwise prune old entries
            $_checkedTables = true;
            $result = mysql_query("SHOW TABLES LIKE '" . CACHE_TABLE . "'", $link);
            if (!$result || mysql_num_rows($result) == 0) {
                // table does not exist... make a new one
                mysql_query("CREATE TABLE " . DB_PREFIX . CACHE_TABLE . " (apicall VARCHAR(64), keyv CHAR(64), expires DATETIME, value MEDIUMBLOB)", $link);
                mysql_query("CREATE INDEX idx_" . DB_PREFIX . CACHE_TABLE . " ON " . CACHE_TABLE . "(keyv)", $link);
            } else {
                // table exists, so delete all outdated cache entries, so they don't gum up the DB
                mysql_query("DELETE FROM " . DB_PREFIX . CACHE_TABLE . " WHERE expires < '" . gmdate("Y-m-d H:i:s") . "'", $link);
            }
            if ($result != false) {
                mysql_free_result($result);
            }
        }
        $key = hash('sha256', $apicall . implode($args));
        if (isset($args["vCode"]) && strpos($args["vCode"], "old_") === 0) {
            $args["userid"] = $args["keyID"];
            $args["apikey"] = substr($args["vCode"], 4);
            unset($args["keyID"]);
            unset($args["vCode"]);
        }
        $result = mysql_query("SELECT expires, value FROM " . DB_PREFIX . CACHE_TABLE . " WHERE apicall = '" . $apicall . "' AND keyv = '" . $key . "' LIMIT 1", $link);
        if ($result != false) {
            if (mysql_num_rows($result) > 0) {
                // yay! got a cached value
                $row = mysql_fetch_assoc($result);
                mysql_free_result($result);
                //echo "result: " .gzuncompress($row['value']);
                if (isset($allApiCalls)) {
                    $allApiCalls[] = array($apicall, $args, "cached");
                }
                return new CacheEntry(new SimpleXMLElement(gzuncompress($row['value']), LIBXML_NOCDATA), 1, get_timeLeft($row['expires']), $key, $apicall, $link);
            }
            mysql_free_result($result);
        }
    }
    // no cached value or it is old... have to do the query proper
    $req = curl_init(API_BASE_URL . $apicall);
    curl_setopt($req, CURLOPT_POST, true);
    curl_setopt($req, CURLOPT_PORT, 443);
    curl_setopt($req, CURLOPT_POSTFIELDS, $args);
    curl_setopt($req, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($req, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($req, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($req, CURLOPT_TIMEOUT, 30);
    curl_setopt($req, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
    //CA cert file
    $resp = curl_exec($req);
    $http_code = curl_getinfo($req, CURLINFO_HTTP_CODE);
    $http_errno = curl_errno($req);
    if (isset($allApiCalls)) {
        $allApiCalls[] = array($apicall, $args, "fetched");
    }
    curl_close($req);
    if ($http_errno == 60) {
        return new CacheEntry("Ssl is not working for Curl");
    }
    if ($http_errno != 0) {
        return new CacheEntry($http_errno);
    }
    if ($http_code != 200) {
        // major api failure
        return new CacheEntry("unexpected response code {$http_code}");
    }
    try {
        $xml = new SimpleXMLElement($resp, LIBXML_NOCDATA);
    } catch (Exception $e) {
        // malformed XML
        return new CacheEntry("malformed XML document");
    }
    if ($xml->error) {
        // error response, don't cache it...
        return new CacheEntry($xml, 0);
    }
    if ($expiresOverride == -1) {
        // skip the cache, don't want to save it and won't be cached
        return new CacheEntry($xml, 0);
    }
    $cachedUntil = (string) $xml->cachedUntil;
    if ($expiresOverride == 0) {
        // other overrides moved into specific files
        /* if ($apicall == "/char/MailMessages.xml.aspx") // only can get full msgs so often
           $cachedUntil = gmdate("Y-m-d H:i:s",time()+7*60*60);*/
    } else {
        $cachedUntil = gmdate("Y-m-d H:i:s", time() + $expiresOverride);
    }
    mysql_query("INSERT INTO " . DB_PREFIX . CACHE_TABLE . " (apicall, keyv, expires, value) " . "VALUES('" . $apicall . "', '" . $key . "', '" . $cachedUntil . "', '" . addslashes(gzcompress($resp, 6)) . "')", $link);
    //                                                        ^ needed for binary data
    return new CacheEntry($xml, 0, get_timeLeft($cachedUntil), $key, $apicall, $link);
}