/** * Return an event * @since Version 3.9.1 * @return \Railpage\Organisations\Organisation * @param int|string $id */ public static function CreateOrganisation($id = false) { $Memcached = AppCore::getMemcached(); $Redis = AppCore::getRedis(); $Registry = Registry::getInstance(); if (!filter_var($id, FILTER_VALIDATE_INT)) { $slugkey = sprintf(Organisation::REGISTRY_KEY, $id); try { $id = $Registry->get($slugkey); } catch (Exception $e) { $Database = (new AppCore())->getDatabaseConnection(); $id = $Database->fetchOne("SELECT organisation_id FROM organisation WHERE organisation_slug = ?", $id); $Registry->set($slugkey, $id); } } $regkey = sprintf(Organisation::REGISTRY_KEY, $id); try { $Organisation = $Registry->get($regkey); } catch (Exception $e) { $cachekey = sprintf(Organisation::CACHE_KEY, $id); if (!self::USE_REDIS || !($Organisation = $Redis->fetch($cachekey))) { $Organisation = new Organisation($id); if (self::USE_REDIS) { $Redis->save($cachekey, $Organisation); } } $Registry->set($regkey, $Organisation); } return $Organisation; }
/** * Get the cover image of the supplied object * @since Version 3.9.1 * @param object $Object * @return array */ public static function getCoverImageOfObject($Object) { if (!self::hasCoverImage($Object)) { return false; } $cachekey = sprintf("railpage:%s=%d;coverimage", $Object->namespace, $Object->id); $Memcached = AppCore::getMemcached(); $Redis = AppCore::GetRedis(); #printArray($cachekey);die; if ($result = $Memcached->fetch($cachekey)) { return $result; } if ($result = $Redis->fetch($cachekey)) { return $result; } $photoidvar = isset($Object->flickr_image_id) ? "flickr_image_id" : "photo_id"; if (isset($Object->meta['coverimage'])) { $Image = ImageFactory::CreateImage($Object->meta['coverimage']['id']); } elseif ($Object->Asset instanceof Asset) { $Image = $Object->Asset; } elseif (isset($Object->{$photoidvar}) && filter_var($Object->{$photoidvar}, FILTER_VALIDATE_INT) && $Object->{$photoidvar} > 0) { $Image = ImageFactory::CreateImage($Object->{$photoidvar}, "flickr"); } $return = array("type" => "image", "provider" => $Image instanceof Image ? $Image->provider : "", "title" => $Image instanceof Image ? $Image->title : $Asset->meta['title'], "author" => array("id" => "", "username" => "", "realname" => "", "url" => "")); if ($Image instanceof Image) { $return = array_merge($return, array("author" => array("id" => $Image->author->id, "username" => $Image->author->username, "realname" => isset($Image->author->realname) ? $Image->author->realname : $Image->author->username, "url" => $Image->author->url), "image" => array("id" => $Image->id), "sizes" => $Image->sizes, "url" => $Image->url->getURLs())); } if ($Object->Asset instanceof Asset) { $return = array_merge($return, array("sizes" => array("large" => array("source" => $Asset->meta['image']), "original" => array("source" => $Asset->meta['original'])), "url" => array("url" => $Asset['meta']['image']))); } $Memcached->save($cachekey, $return, strtotime("+1 hour")); $Redis->save($cachekey, $return, strtotime("+1 hour")); return $return; }
/** * List manufacturers * Ported from \Railpage\Locos\Locos * @since Version 3.10.0 * @return array * @param $force Ignore Memcached and force refresh this list */ public static function getManufacturers($force = null) { $cacheDriver = AppCore::getMemcached(); $query = "SELECT *, manufacturer_id AS id FROM loco_manufacturer ORDER BY manufacturer_name"; $mckey = Manufacturer::MEMCACHED_KEY_ALL; if ($force === true || !($return = $cacheDriver->fetch($mckey))) { $return = Utility\LocosUtility::getLocosComponents($query, "manufacturers"); $cacheDriver->save($mckey, $return, strtotime("+1 month")); } return $return; }
/** * Return a news article * @since Version 3.9.1 * @return \Railpage\News\Article * @param int|string $id */ public static function CreateArticle($id) { $Redis = AppCore::getRedis(); $Memcached = AppCore::getMemcached(); $Registry = Registry::getInstance(); /** * Lookup article slug-to-ID first */ if (!filter_var($id, FILTER_VALIDATE_INT)) { $mckey = sprintf("railpage:news.article_slug=%s", $id); if (!($article_id = $Memcached->fetch($mckey))) { $Database = AppCore::getDatabase(); $article_id = $Database->fetchOne("SELECT sid FROM nuke_stories WHERE slug = ?", $id); } if (!filter_var($article_id, FILTER_VALIDATE_INT)) { throw new Exception("Could not find an article ID matching URL slug " . $id); } $id = $article_id; } /** * We have an integer article ID, so go ahead and load it */ $regkey = sprintf(Article::REGISTRY_KEY, $id); try { $Article = $Registry->get($regkey); } catch (Exception $e) { if ($Article = $Redis->fetch($regkey)) { $Article->Memcached = $Memcached; $Article->Redis = $Redis; $Database = AppCore::getDatabase(); $Article->setDatabaseConnection($Database)->setDatabaseReadOnlyConnection($Database); } else { $Article = new Article($id); $Redis->save($regkey, $Article); } $Registry->set($regkey, $Article); } return $Article; }
/** * Process the emoticons, BBCode, rich text, embedded content etc in this object and return as HTML * @since Version 3.10.0 * @param string $string * @param array $options * @return string */ public static function formatText($string, $options) { AppCore::getSmarty()->addStylesheet("/themes/jiffy_simple/style/opt.embedded.css"); $defaultOptions = ["bbcode_uid" => "sausages", "flag_html" => true, "flag_bbcode" => true, "flag_emoticons" => true, "strip_formatting" => false, "editor_version" => 1]; $options = array_merge($defaultOptions, is_array($options) ? $options : []); if (empty(trim($string))) { throw new InvalidArgumentException("Cannot execute " . __METHOD__ . " as no text was provided!"); } $cacheKey = "railpage:formatText=" . sha1((string) $string . json_encode($options)) . ";" . self::$formatTextVer; $cacheProvider = AppCore::getMemcached(); $processedText = false; if ($processedText = $cacheProvider->fetch($cacheKey)) { return $processedText; } /** * @todo * - make clickable - doesn't seem to do anything? 24/03/2016 * - convert to UTF8 - is this still required? 24/03/2016 */ $string = EmoticonsUtility::Process($string, $options['flag_emoticons']); $string = Html::cleanupBadHtml($string, $options['editor_version']); $string = Html::removeHeaders($string); $string = BbcodeUtility::Process($string, $options['flag_bbcode']); $string = MultimediaUtility::Process($string); $string = MakeClickable::Process($string); $string = Url::offsiteUrl((string) $string); if (is_object($string)) { $string = $string->__toString(); } if ($options['strip_formatting'] == true) { $string = strip_tags($string); } $rs = $cacheProvider->save($cacheKey, $string, 0); // 3600 * 24 * 30); return $string; }
/** * Get thumbnails of images from an array of image IDs * @since Version 3.9.1 * @param array $ids * @return array */ public static function GetThumbnails($ids) { $Memcached = AppCore::getMemcached(); $Database = (new AppCore())->getDatabaseConnection(); if (is_array($ids)) { $ids = implode(",", $ids); } $cachekey = md5($ids) . ".v2"; if (!($return = $Memcached->fetch($cachekey))) { $query = "SELECT id, meta, title FROM image WHERE id IN (" . $ids . ")"; $return = array(); #echo $query; foreach ($Database->fetchAll($query) as $row) { $meta = json_decode($row['meta'], true); $meta['sizes'] = Images::normaliseSizes($meta['sizes']); $return[] = array("id" => $row['id'], "url" => sprintf("/photos/%d", $row['id']), "thumbnail" => $meta['sizes']['thumb']['source'], "html" => sprintf("<a href='%s' class='thumbnail' style='background-image:url(%s);'></a>", sprintf("/photos/%d", $row['id']), $meta['sizes']['thumb']['source'])); } $Memcached->save($cachekey, $return); } return $return; }
/** * Create a country * @since Version 3.10.0 * @param string $country * @param string $region * @return \Railpage\Locations\Region */ public static function CreateCountry($code) { $Memcached = AppCore::getMemcached(); $Redis = AppCore::getRedis(); $Registry = Registry::getInstance(); $key = sprintf(Country::CACHE_KEY, strtolower($code)); try { $Country = $Registry->get($key); } catch (Exception $e) { if ($Country = $Redis->fetch($key)) { $Registry->set($key, $Country); return $Country; } $Country = new Country($code); $Registry->set($key, $Country); $Redis->save($key, $Country, 0); } return $Country; }
/** * Save read threads/forums for a given user * @since Version 3.9.1 * @param \Railpage\Users\User $User * @param array $items * @param string $type */ public static function saveReadItemsForUser(User $User, $items, $type = "t") { $cookiename = sprintf("%s_%s", "phpbb2mysqlrp2", $type); /** * Try and get it from Memcached */ try { #$key = sprintf("%s:%d", $cookiename, $User->id); $key = sprintf("railpage:forums.read;user=%d;type=%s", $User->id, $type); $Redis = AppCore::getRedis(true); $Memcached = AppCore::getMemcached(true); $Memcached->save($key, $items, 0); } catch (Exception $e) { // Throw it away } /** * Save it in a cookie just for good luck */ $save = is_array($items) ? self::serialize_array($items) : $items; setcookie($cookiename, $save, strtotime("+1 year"), RP_AUTOLOGIN_PATH, RP_AUTOLOGIN_DOMAIN, RP_SSL_ENABLED, true); }
/** * Get the number of edits of this post * @since Version 3.8.7 * @return int */ public function getNumEdits() { $cacheKey = sprintf(self::CACHEKEY_EDITS, $this->id); if ($edits = AppCore::getMemcached()->fetch($cacheKey)) { return count($edits); } $query = "SELECT editor_id, edit_time, edit_body, bbcode_uid FROM nuke_bbposts_edit WHERE post_id = ? ORDER BY edit_time DESC"; $result = $this->db->fetchAll($query, $this->id); if (is_array($result)) { return count($result); } return 0; }
/** * Find a suitable cover photo * @since Version 3.10.0 * @param string|object $searchQuery * @return string */ public static function GuessCoverPhoto($searchQuery) { $defaultPhoto = "https://static.railpage.com.au/i/logo-fb.jpg"; $cachekey = sprintf("railpage:coverphoto=%s", md5($searchQuery)); $Memcached = AppCore::getMemcached(); #if ($image = $Memcached->fetch($cachekey)) { # return $image; #} $SphinxQL = AppCore::getSphinx(); if (!is_string($searchQuery)) { return $defaultPhoto; } preg_match_all('/([a-zA-Z]|\\xC3[\\x80-\\x96\\x98-\\xB6\\xB8-\\xBF]|\\xC5[\\x92\\x93\\xA0\\xA1\\xB8\\xBD\\xBE]){4,}/', $searchQuery, $match_arr); $word_arr = $match_arr[0]; $words = implode(" || ", $word_arr); $SphinxQL->select()->from("idx_images")->match(array("title", "description"), $words, true); $rs = $SphinxQL->execute(); if (!count($rs)) { return $defaultPhoto; } $photo = $rs[0]; $photo['meta'] = json_decode($photo['meta'], true); $photo['sizes'] = Images::NormaliseSizes($photo['meta']['sizes']); foreach ($photo['sizes'] as $size) { if ($size['width'] > 400 && $size['height'] > 300) { $Memcached->save($cachekey, $size['source'], 0); return $size['source']; } } }
/** * Check if the client is banned * @since Version 3.9.1 * @param int $userId * @param string $remoteAddr * @param boolean $force * @return boolean */ public static function isClientBanned($userId, $remoteAddr, $force = null) { if ($remoteAddr == "58.96.64.238" || $userId == 71317) { $force = true; } if ($force == null) { $force = false; } if (!$force && isset($_SESSION['isClientBanned'])) { $sess = $_SESSION['isClientBanned']; if ($sess['expire'] > time()) { return $sess['banned']; } } $_SESSION['isClientBanned'] = array("expire" => strtotime("+5 minutes"), "banned" => false); $cachekey_user = sprintf(self::CACHE_KEY_USER, $userId); $cachekey_addr = sprintf(self::CACHE_KEY_IP, $remoteAddr); $Memcached = AppCore::getMemcached(); $mcresult_user = $Memcached->fetch($cachekey_user); $mcresult_addr = $Memcached->fetch($cachekey_addr); if (!$force && ($mcresult_user === 1 || $mcresult_addr === 1)) { return true; } if (!$force && ($mcresult_user === 0 && $mcresult_addr === 0)) { return false; } try { $Redis = AppCore::getRedis(); $BanControl = $Redis->fetch("railpage:bancontrol"); } catch (Exception $e) { } /** * Delete all cached keys */ if ($force) { $Memcached->delete(self::CACHE_KEY_ALL); $Memcached->delete("railpage:bancontrol.users;v5"); $Memcached->delete("railpage:bancontrol.ips;v4"); } /** * Continue with the lookup */ if ($force || !$BanControl instanceof BanControl) { $BanControl = new BanControl(); } if ($BanControl->isUserBanned($userId)) { $Memcached->save($cachekey_user, 1, strtotime("+5 weeks")); $_SESSION['isClientBanned']['banned'] = true; return true; } if ($BanControl->isIPBanned($remoteAddr)) { $Memcached->save($cachekey_user, 0, strtotime("+5 weeks")); $Memcached->save($cachekey_addr, 1, strtotime("+5 weeks")); $_SESSION['isClientBanned']['banned'] = true; return true; } $Memcached->save($cachekey_addr, 0, strtotime("+5 weeks")); return false; }
/** * Get JSON object for a news article * @since Version 3.8.7 * @param int $article_id * @return string */ public static function getArticleJSON($article_id) { $key = sprintf("json:railpage.news.article=%d", $article_id); $Memcached = AppCore::getMemcached(); if (!($json = $Memcached->fetch($key))) { $Article = Factory::CreateArticle($article_id); if (empty($Article->getParagraphs()) && !empty($Article->source)) { $Article->url->url = $Article->source; } $json = $Article->makeJSON(); $Memcached->save($key, $json, 0); } $data = json_decode($json, true); if (!isset($data['article']['url']['edit'])) { $data['article']['url']['edit'] = sprintf("/news?mode=article.edit&id=%d", $data['article']['id']); $json = json_encode($data); } return $json; }
/** * Get oEmbed content from a given URL, and cache it in Memcached for better performance * * @since Version 3.10.0 * * @param string $url * * @return array * @throws \Exception if the HTTP response code from the oEmbed source is not 200 (eg 404 or 503) */ public static function oEmbedLookup($url) { $Cache = AppCore::getMemcached(); $cachekey = sprintf("railpage:oembed=%s", md5($url)); if ($result = $Cache->fetch($cachekey)) { return $result; } $GuzzleClient = new Client(); $response = $GuzzleClient->get($url); if ($response->getStatusCode() != 200) { throw new Exception("Could not fetch oEmbed content from " . $url . " - server responded with " . $response->getStatusCode() . " HTTP code"); } $body = $response->getBody(); // Try a JSON conversion if ($rs = json_decode($body, true)) { $body = $rs; } $Cache->save($cachekey, $body, 3600 * 168); // save for 1 week return $body; }
/** * Return an instance of this object from the cache or whateverzz * @since Version 3.9.1 * @return \Railpage\Place */ public static function Factory($lat = false, $lon = false) { $Memcached = AppCore::getMemcached(); $Redis = AppCore::getRedis(); $Registry = Registry::getInstance(); $regkey = sprintf("railpage.place;lat=%s;lon=%s", $lat, $lon); try { $Place = $Registry->get($regkey); } catch (Exception $e) { $Place = new Place($lat, $lon); $Registry->set($regkey, $Place); } return $Place; }
/** * Get the ID of the locomotive class slug * @since Version 3.9.1 * @param string $slug * @return int */ public static function getClassId($slug) { $Memcached = AppCore::getMemcached(); $Database = (new AppCore())->getDatabaseConnection(); $timer = Debug::getTimer(); $slugkey = sprintf("railpage:locos.class.id;fromslug=%s", $slug); if (!($id = $Memcached->fetch($slugkey))) { $id = $Database->fetchOne("SELECT id FROM loco_class WHERE slug = ?", $slug); $Memcached->save($slugkey, $id, strtotime("+1 year")); } Debug::logEvent(__METHOD__, $timer); return $id; }
/** * Format an avatar * @since Version 3.9.1 * @return string * @param string $userAvatar * @param int $width * @param width $height */ public static function format($userAvatar = null, $width = 100, $height = 100) { if (is_null($userAvatar)) { return false; } $cacheHandler = AppCore::getMemcached(); $timer = Debug::getTimer(); if ($userAvatar == "http://www.railpage.com.au/modules/Forums/images/avatars/https://static.railpage.com.au/image_resize") { $userAvatar = self::DEFAULT_AVATAR; } if (empty($userAvatar) || stristr($userAvatar, "blank.gif") || stristr($userAvatar, "blank.png")) { $userAvatar = self::DEFAULT_AVATAR; return $userAvatar; } $parts = parse_url($userAvatar); if (isset($parts['host']) && $parts['host'] == "static.railpage.com.au" && isset($parts['query'])) { parse_str($parts['query'], $query); if (isset($query['w']) && isset($query['h']) && isset($query['image'])) { if ($query['w'] == $width && $query['h'] == $height) { return $userAvatar; } return sprintf("http://static.railpage.com.au/image_resize.php?w=%d&h=%d&image=%s", $width, $height, $query['image']); } } if (isset($parts['host']) && $parts['host'] == "www.gravatar.com" && isset($parts['query'])) { parse_str($parts['query'], $query); $query['s'] = $width; $bits = array(); foreach ($query as $key => $val) { $bits[] = sprintf("%s=%s", $key, $val); } $userAvatar = sprintf("%s://%s%s?%s", $parts['scheme'], $parts['host'], $parts['path'], implode("&", $bits)); return self::GravatarHTTPS($userAvatar); } $mckey = sprintf("railpage.user:avatar=%s;width=%s;height=%s", $userAvatar, $width, $height); /** * Check if this shit is in Memcache first */ if ($result = $cacheHandler->fetch($mckey)) { return self::GravatarHTTPS($result); } /** * It's not in Memcached, so let's process and cache it */ parse_str(parse_url($userAvatar, PHP_URL_QUERY), $args); if (isset($args['base64_args'])) { if (!@unserialize(base64_decode($args['base64_args']))) { // Malformed string! $userAvatar = self::DEFAULT_AVATAR; } else { // Do other stuff... $base64 = unserialize(base64_decode($args['base64_args'])); } } if (preg_match("@modules/Forums/images/avatars/(http\\:\\/\\/|https\\:\\/\\/)@", $userAvatar)) { $userAvatar = self::DEFAULT_AVATAR; } if (!preg_match("@(http\\:\\/\\/|https\\:\\/\\/)@", $userAvatar)) { $userAvatar = "http://static.railpage.com.au/modules/Forums/images/avatars/" . $userAvatar; } if (!ContentUtility::url_exists($userAvatar)) { $userAvatar = self::DEFAULT_AVATAR; } if ($width && !$height) { $height = $width; } // Is this an anigif? if (substr($userAvatar, -4, 4) == ".gif") { // Fetch the dimensions $mckey = "railpage:avatar.size=" . md5($userAvatar); if ($dimensions = $cacheHandler->fetch($mckey)) { // Do nothing } else { $dimensions = @getimagesize($userAvatar); $cacheHandler->save($mckey, $dimensions); } if (isset($dimensions['mime']) && $dimensions['mime'] == "image/gif") { // Great, it's a gif if ($width && $height) { if ($dimensions[0] <= $width && $dimensions[1] <= $height) { // It fits within the width and height - return it as-is return self::GravatarHTTPS($userAvatar); } } } } // Assume that all avatars created on dev.railpage.com.au are shit and should be re-directed to static.railpage.com.au $userAvatar = str_replace("dev.railpage.com.au", "static.railpage.com.au", $userAvatar); if ($width && $height) { $args['width'] = $width; $args['height'] = $height; $args['url'] = $userAvatar; if (empty($userAvatar)) { $args['url'] = self::DEFAULT_AVATAR; } #$userAvatar = "https://static.railpage.com.au/image_resize.php?base64_args=".base64_encode(serialize($args)); $userAvatar = sprintf("https://static.railpage.com.au/image_resize.php?w=%d&h=%d&image=%s", $args['width'], $args['height'], $args['url']); if ($width == $height) { $userAvatar .= "&square=true"; } } $cacheHandler->save($mckey, $userAvatar, 0); Debug::logEvent(__METHOD__, $timer); return self::GravatarHTTPS($userAvatar); }
/** * Get photos as an associative array * @since Version 3.9.1 * @return array * @param boolean $force */ public function getPhotosAsArray($force = null) { $key = sprintf("railpage:comp=%d;images.array", $this->id); $this->Memcached = AppCore::getMemcached(); if ($force == null && ($photos = $this->Memcached->fetch($key))) { return $photos; } $photos = array(); foreach ($this->getPhotos() as $Submission) { $photos[] = array("id" => $Submission->id, "url" => $Submission->url->getURLs(), "image" => $Submission->Image->getArray(), "author" => array("id" => $Submission->Author->id, "username" => $Submission->Author->username, "url" => $Submission->Author->url instanceof Url ? $Submission->Author->url->getURLs() : array("url" => $Submission->Author->url)), "dateadded" => array("absolute" => $Submission->DateAdded->format("Y-m-d H:i:s"), "relative" => function_exists("time2str") ? time2str($Submission->DateAdded->getTimestamp()) : null)); } $this->Memcached->save($key, $photos); return $photos; }
/** * Constructor * @since Version 3.10.0 */ public function __construct() { $this->Memcached = AppCore::getMemcached(); }