You are here

class InstapageCmsPluginPageModel in Instapage plugin 8.3

Same name and namespace in other branches
  1. 7.3 core/models/InstapageCmsPluginPageModel.php \InstapageCmsPluginPageModel

Class responsible for managing the landing pages.

Hierarchy

Expanded class hierarchy of InstapageCmsPluginPageModel

File

core/models/InstapageCmsPluginPageModel.php, line 6

View source
class InstapageCmsPluginPageModel {

  /**
   * @var object Class instance.
   */
  private static $pageModel = null;

  /**
   * @var int Page statistics cache duration in minutes.
   */
  private static $statCacheDuration = 15;

  /**
   * Gets the class instance.
   *
   * @return object Class instance.
   */
  public static function getInstance() {
    if (self::$pageModel === null) {
      self::$pageModel = new InstapageCmsPluginPageModel();
    }
    return self::$pageModel;
  }

  /**
   * Updates the page baset on passed $data object.
   *
   * @param object $data Data object.
   *
   * @return integer|boolean Insert ID of false on error.
   */
  public function update($data) {
    $id = isset($data->id) ? $data->id : 0;
    $instapageId = isset($data->landingPageId) ? $data->landingPageId : null;
    $type = isset($data->type) ? $data->type : false;
    $slug = isset($data->slug) ? $data->slug : false;
    $enterpriseUrl = InstapageCmsPluginConnector::getHomeURL();
    if ($slug) {
      $enterpriseUrl .= '/' . $slug;
    }
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'INSERT INTO ' . $db->pagesTable . ' VALUES(%s, %s, %s, %s, NOW(), \'\', NULL, %s) ON DUPLICATE KEY UPDATE instapage_id = %s, slug = %s, type = %s, time = NOW(), stats_cache = \'\', stats_cache_expires = NULL, enterprise_url = %s';
    if ($db
      ->query($sql, $id, $instapageId, $slug, $type, $enterpriseUrl, $instapageId, $slug, $type, $enterpriseUrl)) {
      return $id == 0 ? $db
        ->lastInsertId() : $id;
    }
    else {
      return false;
    }
  }

  /**
   * Gets all the stored pages.
   *
   * @param array $fields Fields to retrieve. Default: array('*').
   * @param array $conditions. List of conditions. Logical operator between conditions: AND.
   *
   * @return array Lst of results.
   */
  public function getAll($fields = array(
    '*',
  ), $conditions = array()) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable;
    if (count($conditions)) {
      $sql .= ' WHERE ' . implode(' AND ', $conditions);
    }
    return $db
      ->getResults($sql);
  }

  /**
   * Gest the single page based on ID.
   *
   * @param int $id ID of the page.
   * @param array $fields List of fields to retrieve. Default: array('*').
   *
   * @return object Page object.
   */
  public function get($id, $fields = array(
    '*',
  )) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable . ' WHERE id = \'' . $id . '\'';
    return $db
      ->getRow($sql);
  }

  /**
   * Gest the single page based on slug.
   *
   * @param string $slug Slug of the page.
   * @param array $fields List of fields to retrieve. Default: array('*').
   *
   * @return object Page object.
   */
  public function getBySlug($slug, $fields = array(
    '*',
  )) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable . ' WHERE slug = %s AND type=\'page\'';
    return $db
      ->getRow($sql, $slug);
  }

  /**
   * Gest the single page based on type and slug.
   *
   * @param string $type Type of the page. ('page'|'home'|'404').
   * @param string $slug Slug of the page.
   * @param array $fields List of fields to retrieve. Default: array('*').
   *
   * @return object Page object.
   */
  public function getByType($type, $slug = '', $fields = array(
    '*',
  )) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable . ' WHERE type = %s';
    if ($slug) {
      $sql = $sql . ' AND slug = %s';
      return $db
        ->getRow($sql, $type, $slug);
    }
    else {
      return $db
        ->getRow($sql, $type);
    }
  }

  /**
   * Gest the single page based on ID in Instapage app.
   *
   * @param int $instapageId ID in Instapage app.
   * @param array $fields List of fields to retrieve. Default: array('*').
   *
   * @return array List of page objects.
   */
  public function getByInstapageId($instapageId, $fields = array(
    '*',
  )) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable . ' WHERE instapage_id = ' . $instapageId;
    return $db
      ->getResults($sql);
  }

  /**
   * Gets the cached statistics for pages.
   *
   * @param array $ids List of page IDs.
   *
   * @return array List of objects with stats cache informations.
   */
  public function getPageStatsCache($ids) {
    if (!is_array($ids) || !count($ids)) {
      return null;
    }
    $db = InstapageCmsPluginDBModel::getInstance();
    foreach ($ids as &$item) {
      $item = intval($item);
    }
    $idsSet = implode(', ', $ids);
    $expireInSeconds = self::$statCacheDuration * 60;
    $sql = 'SELECT instapage_id, stats_cache FROM ' . $db->pagesTable . ' WHERE instapage_id IN(' . $idsSet . ') AND stats_cache_expires + ' . $expireInSeconds . ' > ' . time();
    $results = $db
      ->getResults($sql);
    $stats = array();
    if ($results) {
      foreach ($results as &$item) {
        $stats[$item->instapage_id] = json_decode($item->stats_cache);
      }
      return $stats;
    }
    return array();
  }

  /**
   * Sends a request to publish a page in Instapage app.
   *
   * @param object $data Page object.
   *
   * @return string JSON object with API response.
   */
  public function publishPage($data) {
    $api = InstapageCmsPluginAPIModel::getInstance();
    $subaccount = InstapageCmsPluginSubaccountModel::getInstance();
    $url = $data->slug ? InstapageCmsPluginConnector::getHomeURL() . '/' . $data->slug : InstapageCmsPluginConnector::getHomeURL();
    $url = InstapageCmsPluginHelper::prepareUrlForUpdate($url);
    $tokens = isset($data->apiTokens) ? $data->apiTokens : false;
    $success = true;
    if (!$tokens) {
      $tokens = $subaccount
        ->getAllTokens();
    }
    $oldPageId = isset($data->id) ? $data->id : null;
    $newInstapageId = isset($data->landingPageId) ? $data->landingPageId : null;
    if ($oldPageId) {
      $oldPage = $this
        ->get($oldPageId, array(
        'instapage_id',
      ));
      if ($oldPage->instapage_id != $newInstapageId) {
        $apiData = array(
          'page' => $oldPage->instapage_id,
          'url' => '',
          'publish' => 0,
        );
        $headers = array(
          'accountkeys' => InstapageCmsPluginHelper::getAuthHeader($tokens),
        );
        $responseJson = $api
          ->apiCall('page/edit', $apiData, $headers);
        $response = json_decode($responseJson);
        if (!InstapageCmsPluginHelper::checkResponse($response, null, false) || !$response->success) {
          $success = false;
        }
      }
    }
    if ($success) {
      $apiData = array(
        'page' => $data->landingPageId,
        'url' => $url,
        'publish' => 1,
      );
      $headers = array(
        'accountkeys' => InstapageCmsPluginHelper::getAuthHeader($tokens),
      );
      $responseJson = $api
        ->apiCall('page/edit', $apiData, $headers);
      $response = json_decode($responseJson);
    }
    if (!$success || !InstapageCmsPluginHelper::checkResponse($response, null, false) || !$response->success) {
      if (isset($response->message) && $response->message !== '') {
        return InstapageCmsPluginHelper::formatJsonMessage(InstapageCmsPluginConnector::lang($response->message), 'ERROR');
      }
      else {
        return InstapageCmsPluginHelper::formatJsonMessage(InstapageCmsPluginConnector::lang('There was an error during page update process.'), 'ERROR');
      }
      return false;
    }
    $updatedId = $this
      ->update($data);
    if ($updatedId) {
      return json_encode((object) array(
        'status' => 'OK',
        'message' => InstapageCmsPluginConnector::lang('Page updated successfully.'),
        'updatedId' => $updatedId,
      ));
    }
    else {
      return InstapageCmsPluginHelper::formatJsonMessage(InstapageCmsPluginConnector::lang('There was a database error during page update process.'), 'ERROR');
    }
  }

  /**
   * Migrates the depracated pages to current DB structure.
   *
   * @param array $data List of pages to migrate.
   *
   * @return array List of messages to display as a migration raport.
   */
  public function migrateDeprecatedData($data) {
    InstapageCmsPluginHelper::writeDiagnostics($data, 'Migration data');
    $raport = array();
    if (!is_array($data) || !count($data)) {
      return $raport;
    }
    foreach ($data as $deprecatedPage) {
      if ($deprecatedPage->type == 'home') {
        $deprecatedPage->slug = '';
      }
      $landingPagesById = $this
        ->getByInstapageId($deprecatedPage->landingPageId);
      $landingPagesBySlug = null;
      $landingPagesByType = null;
      if (count($landingPagesById)) {
        $newLandingPage = array_pop($landingPagesById);
        $raport[] = InstapageCmsPluginConnector::lang('Old version of page (slug: %s, Instapage ID: %s) is present in new database (slug: %s) and won\'t be migrated.', $deprecatedPage->slug, $deprecatedPage->landingPageId, $newLandingPage->slug);
        continue;
      }
      if ($deprecatedPage->slug && $deprecatedPage->type == 'page') {
        $landingPagesBySlug = $this
          ->getBySlug($deprecatedPage->slug);
      }
      if ($landingPagesBySlug) {
        $newLandingPage = $landingPagesBySlug;
        $raport[] = InstapageCmsPluginConnector::lang('Slug: %s is already taken in new database. Old page (slug: %s, Instapage ID: %s) won\'t be migrated.', $deprecatedPage->slug, $deprecatedPage->slug, $deprecatedPage->landingPageId);
        continue;
      }
      if ($deprecatedPage->type !== 'page') {
        $landingPagesByType = $this
          ->getByType($deprecatedPage->type);
      }
      if ($landingPagesByType) {
        $newLandingPage = $landingPagesByType;
        $raport[] = InstapageCmsPluginConnector::lang('One %s page already exists in new database. Old page (slug: %s, Instapage ID: %s) won\'t be migrated.', $deprecatedPage->type, $deprecatedPage->slug, $deprecatedPage->landingPageId);
        continue;
      }
      if ($this
        ->update($deprecatedPage)) {
        $raport[] = InstapageCmsPluginConnector::lang('Old version of page (slug: %s, Instapage ID: %s) successfully migrated.', $deprecatedPage->slug, $deprecatedPage->landingPageId);
      }
      else {
        $raport[] = InstapageCmsPluginConnector::lang('Old version of page (slug: %s, Instapage ID: %s) cannot be migrated due to database error.', $deprecatedPage->slug, $deprecatedPage->landingPageId);
      }
    }
    InstapageCmsPluginHelper::writeDiagnostics($raport, 'Migration raport');
    return $raport;
  }

  /**
   * Saves the statistics of the page as a cache.
   *
   * @param array $data Lst of elements to save.
   */
  public function savePageStatsCache($data) {
    $db = InstapageCmsPluginDBModel::getInstance();
    foreach ($data as $key => $item) {
      $sql = 'UPDATE ' . $db->pagesTable . ' SET stats_cache = %s, stats_cache_expires = ' . time() . ' WHERE instapage_id = %s';
      $db
        ->query($sql, json_encode($item), $key);
    }
  }

  /**
   * Gets a landing page saved as a homepage.
   *
   * @param array $fields List of fields to retrieve. Default: array('*').
   *
   * @return object Page object.
   */
  public function getHomepage($fields = array(
    '*',
  )) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable . ' WHERE type=\'home\'';
    return $db
      ->getRow($sql);
  }

  /**
   * Gets a landing page saved as a 404 page.
   *
   * @param array $fields List of fields to retrieve. Default: array('*').
   *
   * @return object Page object.
   */
  public function get404($fields = array(
    '*',
  )) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $db->pagesTable . ' WHERE type=\'404\'';
    return $db
      ->getRow($sql);
  }

  /**
   * Gets the data about landing pages stores in local database and completes them with data from Instapage app.
   *
   * @param array localData List of pages stored locally. Data will be changed during the process.
   *
   * @param array $appData List of information from the Instapage app.
   */
  public function mergeListPagesResults(&$localData, $appData) {
    foreach ($localData as &$localItem) {
      $instapageId = $localItem->instapage_id;
      $appItem = $this
        ->getPageFromArray($instapageId, $appData);
      if (!is_null($appItem)) {
        $localItem->screenshot = $appItem->screenshot;
        $localItem->title = $appItem->title;
        $localItem->subaccount = $appItem->subaccount;
      }
    }
  }

  /**
   * Checks (and returns) if a landing page should be displayed instead of normal content served by CMS.
   *
   * @param string $type Type of page to check ('page', 'home' or '404').
   * @param string $slug Slug to check. Default: ''.
   *
   * @return string HTML to display.
   */
  public function check($type, $slug = '') {
    if (!InstapageCmsPluginConnector::isHtmlReplaceNecessary()) {
      return;
    }
    $result = $this
      ->getByType($type, $slug, array(
      'instapage_id',
      'slug',
      'enterprise_url',
    ));
    if (!$result) {
      return;
    }
    $result->slug = $result->slug ? $result->slug : $slug;
    $result->enterprise_url = $result->enterprise_url ? $result->enterprise_url : InstapageCmsPluginConnector::getHomeURL() . '/' . $result->slug;
    $result->enterprise_url = rtrim($result->enterprise_url, '/');
    return $result;
  }

  /**
   * Displays the landing page.
   *
   * @param object $page Landing page to display.
   * @param int $forcedStatus Status to be set as a header. Default: null.
   */
  public function display($page, $forcedStatus = null) {
    require_once __DIR__ . '/../modules/lpAjaxLoader/InstapageCmsPluginLPAjaxLoaderController.php';
    $lpAjaxLoaderController = new InstapageCmsPluginLPAjaxLoaderController();
    $instapageId = $page->instapage_id;
    $slug = $page->slug;
    $host = parse_url($page->enterprise_url, PHP_URL_HOST);
    InstapageCmsPluginHelper::writeDiagnostics($slug . ' : ' . $instapageId, 'slug : instapage_id');
    $api = InstapageCmsPluginAPIModel::getInstance();
    $querySufix = '';
    $cookies = $_COOKIE;
    if (!empty($_GET)) {
      if ($lpAjaxLoaderController
        ->shouldDecodeQuery()) {
        $querySufix = '?' . base64_decode($_GET['b64']);
      }
      else {
        $querySufix = '?' . http_build_query($_GET);
      }
    }
    elseif (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
      $querySufix = '?' . $_SERVER['QUERY_STRING'];
    }
    if (is_array($cookies) && count($cookies)) {
      $cookiesWeNeed = array(
        "instapage-variant-{$instapageId}",
      );
      foreach ($cookies as $key => $value) {
        if (!in_array($key, $cookiesWeNeed)) {
          unset($cookies[$key]);
        }
      }
    }
    $url = preg_replace('/https?:\\/\\/' . $host . '/', INSTAPAGE_ENTERPRISE_ENDPOINT, $page->enterprise_url);
    $url .= $querySufix;
    $url = InstapageCmsPluginConnector::getURLWithSelectedProtocol($url);
    $enterpriseCallResult = $api
      ->enterpriseCall($url, $host, $cookies);
    $html = $this
      ->getLandingPageHTMLFromTheApp($enterpriseCallResult);
    $this
      ->setVariantCookie($enterpriseCallResult, $instapageId);
    if ($lpAjaxLoaderController
      ->shouldBeUsed($url)) {
      $html = $lpAjaxLoaderController
        ->injectScript($html);
      $html = $lpAjaxLoaderController
        ->addDisplayNoneOnBody($html);
    }
    if ($forcedStatus) {
      $status = $forcedStatus;
    }
    else {
      $status = isset($enterpriseCallResult['code']) ? $enterpriseCallResult['code'] : 200;
    }
    if ($html) {
      ob_start();
      InstapageCmsPluginHelper::disableCaching();
      InstapageCmsPluginHelper::httpResponseCode($status);
      print $html;
      ob_end_flush();
      die;
    }
    else {
      return false;
    }
  }

  /**
   * Gets and prepares Landing Page HTML from app (from request to so called enterprise)
   *
   * @param array $enterpriseCallResult Result from enterpriseCall() method
   * @return string
   */
  public function getLandingPageHTMLFromTheApp($enterpriseCallResult) {
    $html = isset($enterpriseCallResult['body']) ? $enterpriseCallResult['body'] : false;
    $html = $this
      ->disableCloudFlareScriptReplace($html);
    $html = $this
      ->fixHtmlHead($html);
    return $html;
  }

  /**
   * Set cookie with variant value
   *
   * @param array $enterpriseCallResult Result from enterpriseCall() method
   * @param int $instapageId
   */
  public function setVariantCookie($enterpriseCallResult, $instapageId) {
    $pageserverCookie = isset($enterpriseCallResult['headers']['set-cookie']) ? $enterpriseCallResult['headers']['set-cookie'] : '';
    if (is_array($pageserverCookie)) {
      $pageserverCookie = array_pop($pageserverCookie);
    }
    $instapageVariant = InstapageCmsPluginHelper::getVariant((string) $pageserverCookie);
    if (!empty($instapageVariant)) {
      $variantCookieName = "instapage-variant-{$instapageId}";
      $variantCookieOptions = [
        'expires' => strtotime('+12 month'),
        'path' => '/',
        'domain' => '',
      ];
      if (InstapageCmsPluginConnector::isSSL()) {
        $variantCookieOptions['samesite'] = 'None';
        $variantCookieOptions['secure'] = InstapageCmsPluginConnector::isSSL();
      }
      if (version_compare(phpversion(), '7.3', '<')) {
        if (InstapageCmsPluginConnector::isSSL()) {
          setcookie($variantCookieName, $instapageVariant, $variantCookieOptions['expires'], $variantCookieOptions['path'] . '; samesite=' . $variantCookieOptions['samesite'], $variantCookieOptions['domain'], $variantCookieOptions['secure']);
        }
        else {
          setcookie($variantCookieName, $instapageVariant, $variantCookieOptions['expires'], $variantCookieOptions['path'], $variantCookieOptions['domain']);
        }
      }
      else {
        setcookie($variantCookieName, $instapageVariant, $variantCookieOptions);
      }
    }
  }

  /**
   * Deletes a page from local DB.
   *
   * @param int $id ID of a page to be deleted.
   */
  public function delete($id) {
    $db = InstapageCmsPluginDBModel::getInstance();
    $sql = 'DELETE FROM ' . $db->pagesTable . ' WHERE id = %s';
    return $db
      ->query($sql, $id);
  }

  /**
   * Gets the page object from an array of page objects.
   *
   * @param int $id ID of a page.
   * @param array $array List of page objects.
   *
   * @return object|null Page object or null if no pages found.
   */
  private function getPageFromArray($id, $array) {
    if (is_array($array)) {
      foreach ($array as $item) {
        if ($item->id == $id) {
          return $item;
        }
      }
    }
    return null;
  }

  /**
   * Composes a random slug.
   *
   * @param bool $prefix Do you want to add a prefix?
   *
   * @return string Random slug.
   */
  public function getRandomSlug($prefix = true) {
    $randomPrefix = 'random-url-';
    $randomSufixSet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randomSufixLength = 10;
    $randomString = '';
    for ($i = 0; $i < $randomSufixLength; $i++) {
      $randomString .= $randomSufixSet[rand(0, strlen($randomSufixSet) - 1)];
    }
    return $prefix ? $randomPrefix . $randomString : $randomString;
  }

  /**
   * Removes the CloudFlare JS from a landing page content.
   *
   * @param string $html HTML of a landing page.
   *
   * @return string HTML without CloudFlare script.
   */
  private function disableCloudFlareScriptReplace($html) {
    $pattern = '/(<script)(type="text\\/javascript")?(.*?)>/';
    return preg_replace($pattern, "\$1\$2 data-cfasync=\"false\" \$3>", $html);
  }

  /**
   * Sets up the proper URL for Instapage proxy, if it is enabled.
   *
   * @param string $html HTML to be fixed.
   *
   * @return string HTML with propely set proxy URLs.
   */
  public function fixHtmlHead($html) {
    $useProxy = InstapageCmsPluginHelper::getOption('crossOrigin', false);
    if ($useProxy) {
      $html = str_replace('PROXY_SERVICES', str_replace(array(
        'http://',
        'https://',
      ), array(
        '//',
        '//',
      ), InstapageCmsPluginConnector::getHomeURL()) . "/instapage-proxy-services?url=", $html);
    }
    $searchArray = array(
      '<meta name="iy453p9485yheisruhs5" content="" />',
      '<meta name="robots" content="noindex, nofollow" />',
    );
    if (strpos($html, $searchArray[0]) !== false) {
      $html = str_replace($searchArray, '', $html);
    }
    return $html;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
InstapageCmsPluginPageModel::$pageModel private static property
InstapageCmsPluginPageModel::$statCacheDuration private static property
InstapageCmsPluginPageModel::check public function Checks (and returns) if a landing page should be displayed instead of normal content served by CMS.
InstapageCmsPluginPageModel::delete public function Deletes a page from local DB.
InstapageCmsPluginPageModel::disableCloudFlareScriptReplace private function Removes the CloudFlare JS from a landing page content.
InstapageCmsPluginPageModel::display public function Displays the landing page.
InstapageCmsPluginPageModel::fixHtmlHead public function Sets up the proper URL for Instapage proxy, if it is enabled.
InstapageCmsPluginPageModel::get public function Gest the single page based on ID.
InstapageCmsPluginPageModel::get404 public function Gets a landing page saved as a 404 page.
InstapageCmsPluginPageModel::getAll public function Gets all the stored pages.
InstapageCmsPluginPageModel::getByInstapageId public function Gest the single page based on ID in Instapage app.
InstapageCmsPluginPageModel::getBySlug public function Gest the single page based on slug.
InstapageCmsPluginPageModel::getByType public function Gest the single page based on type and slug.
InstapageCmsPluginPageModel::getHomepage public function Gets a landing page saved as a homepage.
InstapageCmsPluginPageModel::getInstance public static function Gets the class instance.
InstapageCmsPluginPageModel::getLandingPageHTMLFromTheApp public function Gets and prepares Landing Page HTML from app (from request to so called enterprise)
InstapageCmsPluginPageModel::getPageFromArray private function Gets the page object from an array of page objects.
InstapageCmsPluginPageModel::getPageStatsCache public function Gets the cached statistics for pages.
InstapageCmsPluginPageModel::getRandomSlug public function Composes a random slug.
InstapageCmsPluginPageModel::mergeListPagesResults public function Gets the data about landing pages stores in local database and completes them with data from Instapage app.
InstapageCmsPluginPageModel::migrateDeprecatedData public function Migrates the depracated pages to current DB structure.
InstapageCmsPluginPageModel::publishPage public function Sends a request to publish a page in Instapage app.
InstapageCmsPluginPageModel::savePageStatsCache public function Saves the statistics of the page as a cache.
InstapageCmsPluginPageModel::setVariantCookie public function Set cookie with variant value
InstapageCmsPluginPageModel::update public function Updates the page baset on passed $data object.