Version Notes
Plugin corresponds to version 6.0.2 of the Bazaarvoice platform
Download this release
Release Info
Developer | BV DTS |
Extension | Bazaarvoice_Connector |
Version | 6.3.0 |
Comparing to | |
See all releases |
Code changes from version 6.2.0 to 6.3.0
- app/code/local/Bazaarvoice/Connector/Block/Questions.php +23 -5
- app/code/local/Bazaarvoice/Connector/Block/Reviews.php +23 -5
- app/code/local/Bazaarvoice/Connector/Model/ExportPurchaseFeed.php +11 -11
- app/code/local/Bazaarvoice/Connector/etc/config.xml +1 -1
- lib/Bazaarvoice/BVFooter.php +129 -0
- lib/Bazaarvoice/BVUtility.php +254 -0
- lib/Bazaarvoice/bvseosdk.php +949 -519
- package.xml +4 -4
app/code/local/Bazaarvoice/Connector/Block/Questions.php
CHANGED
@@ -38,13 +38,31 @@ class Bazaarvoice_Connector_Block_Questions extends Mage_Core_Block_Template
|
|
38 |
str_replace(' ', '_', Mage::getStoreConfig('bazaarvoice/general/deployment_zone')) .
|
39 |
'-' . Mage::getStoreConfig('bazaarvoice/general/locale');
|
40 |
}
|
41 |
-
$
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
'cloud_key' => Mage::getStoreConfig('bazaarvoice/general/cloud_seo_key'), // BV provided value
|
|
|
|
|
45 |
'staging' => (Mage::getStoreConfig('bazaarvoice/general/environment') == "staging" ? TRUE : FALSE)
|
46 |
-
)
|
47 |
-
$
|
|
|
|
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
return $seoContent;
|
38 |
str_replace(' ', '_', Mage::getStoreConfig('bazaarvoice/general/deployment_zone')) .
|
39 |
'-' . Mage::getStoreConfig('bazaarvoice/general/locale');
|
40 |
}
|
41 |
+
$product = Mage::registry('current_product');
|
42 |
+
$productUrl = Mage::helper('core/url')->getCurrentUrl();
|
43 |
+
$parts = parse_url($productUrl);
|
44 |
+
if(isset($parts['query'])) {
|
45 |
+
parse_str($parts['query'], $query);
|
46 |
+
unset($query['bvrrp']);
|
47 |
+
$baseUrl = $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '?' . http_build_query($query);
|
48 |
+
} else {
|
49 |
+
$baseUrl = $productUrl;
|
50 |
+
}
|
51 |
+
$params = array(
|
52 |
+
'seo_sdk_enabled' => TRUE,
|
53 |
+
'bv_root_folder' => $deploymentZoneId, // replace with your display code (BV provided)
|
54 |
+
'subject_id' => Mage::helper('bazaarvoice')->getProductId($product), // replace with product id
|
55 |
'cloud_key' => Mage::getStoreConfig('bazaarvoice/general/cloud_seo_key'), // BV provided value
|
56 |
+
'base_url' => $baseUrl,
|
57 |
+
'page_url' => $productUrl,
|
58 |
'staging' => (Mage::getStoreConfig('bazaarvoice/general/environment') == "staging" ? TRUE : FALSE)
|
59 |
+
);
|
60 |
+
if($this->getRequest()->getParam('bvreveal') == 'debug')
|
61 |
+
$params['bvreveal'] = 'debug';
|
62 |
+
|
63 |
+
$bv = new BV($params);
|
64 |
+
$seoContent = $bv->questions->getContent();
|
65 |
+
$seoContent .= '<!-- BV Questions Parameters: ' . print_r($params, 1) . '-->';
|
66 |
}
|
67 |
|
68 |
return $seoContent;
|
app/code/local/Bazaarvoice/Connector/Block/Reviews.php
CHANGED
@@ -38,13 +38,31 @@ class Bazaarvoice_Connector_Block_Reviews extends Mage_Core_Block_Template
|
|
38 |
str_replace(' ', '_', Mage::getStoreConfig('bazaarvoice/general/deployment_zone')) .
|
39 |
'-' . Mage::getStoreConfig('bazaarvoice/general/locale');
|
40 |
}
|
41 |
-
$
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
'cloud_key' => Mage::getStoreConfig('bazaarvoice/general/cloud_seo_key'), // BV provided value
|
|
|
|
|
45 |
'staging' => (Mage::getStoreConfig('bazaarvoice/general/environment') == "staging" ? TRUE : FALSE)
|
46 |
-
)
|
47 |
-
$
|
|
|
|
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
return $seoContent;
|
38 |
str_replace(' ', '_', Mage::getStoreConfig('bazaarvoice/general/deployment_zone')) .
|
39 |
'-' . Mage::getStoreConfig('bazaarvoice/general/locale');
|
40 |
}
|
41 |
+
$product = Mage::registry('current_product');
|
42 |
+
$productUrl = Mage::helper('core/url')->getCurrentUrl();
|
43 |
+
$parts = parse_url($productUrl);
|
44 |
+
if(isset($parts['query'])) {
|
45 |
+
parse_str($parts['query'], $query);
|
46 |
+
unset($query['bvrrp']);
|
47 |
+
$baseUrl = $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '?' . http_build_query($query);
|
48 |
+
} else {
|
49 |
+
$baseUrl = $productUrl;
|
50 |
+
}
|
51 |
+
$params = array(
|
52 |
+
'seo_sdk_enabled' => TRUE,
|
53 |
+
'bv_root_folder' => $deploymentZoneId, // replace with your display code (BV provided)
|
54 |
+
'subject_id' => Mage::helper('bazaarvoice')->getProductId($product), // replace with product id
|
55 |
'cloud_key' => Mage::getStoreConfig('bazaarvoice/general/cloud_seo_key'), // BV provided value
|
56 |
+
'base_url' => $baseUrl,
|
57 |
+
'page_url' => $productUrl,
|
58 |
'staging' => (Mage::getStoreConfig('bazaarvoice/general/environment') == "staging" ? TRUE : FALSE)
|
59 |
+
);
|
60 |
+
if($this->getRequest()->getParam('bvreveal') == 'debug')
|
61 |
+
$params['bvreveal'] = 'debug';
|
62 |
+
|
63 |
+
$bv = new BV($params);
|
64 |
+
$seoContent = $bv->reviews->getContent();
|
65 |
+
$seoContent .= '<!-- BV Reviews Parameters: ' . print_r($params, 1) . '-->';
|
66 |
}
|
67 |
|
68 |
return $seoContent;
|
app/code/local/Bazaarvoice/Connector/Model/ExportPurchaseFeed.php
CHANGED
@@ -330,7 +330,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
330 |
* @param Mage_Core_Model_Website $website
|
331 |
* @return int
|
332 |
*/
|
333 |
-
|
334 |
{
|
335 |
// Get a collection of all the orders
|
336 |
$orders = Mage::getModel('sales/order')->getCollection();
|
@@ -370,7 +370,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
370 |
* @param Mage_Core_Model_Store_Group $group
|
371 |
* @return int
|
372 |
*/
|
373 |
-
|
374 |
{
|
375 |
// Get a collection of all the orders
|
376 |
$orders = Mage::getModel('sales/order')->getCollection();
|
@@ -410,7 +410,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
410 |
* @param Mage_Core_Model_Store $store
|
411 |
* @return int
|
412 |
*/
|
413 |
-
|
414 |
{
|
415 |
// Get a collection of all the orders
|
416 |
$orders = Mage::getModel('sales/order')->getCollection();
|
@@ -446,7 +446,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
446 |
* @param $orders
|
447 |
* @return int
|
448 |
*/
|
449 |
-
|
450 |
{
|
451 |
// Get ref to BV helper
|
452 |
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
@@ -568,7 +568,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
568 |
}
|
569 |
}
|
570 |
|
571 |
-
|
572 |
{
|
573 |
return "\nOrder {Id: " . $order->getIncrementId()
|
574 |
. "\n\tCustomerId: " . $order->getCustomerId()
|
@@ -583,7 +583,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
583 |
. "\n}";
|
584 |
}
|
585 |
|
586 |
-
|
587 |
{
|
588 |
$timestamp = strtotime($order->getCreatedAtDate());
|
589 |
|
@@ -594,17 +594,17 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
594 |
return date('c', $timestamp);
|
595 |
}
|
596 |
|
597 |
-
|
598 |
{
|
599 |
return date('Y-m-d', strtotime(date('Y-m-d', time()) . ' -' . self::NUM_DAYS_LOOKBACK . ' days'));
|
600 |
}
|
601 |
|
602 |
-
|
603 |
{
|
604 |
return time() - (24 * 60 * 60 * $delayDaysSinceEvent);
|
605 |
}
|
606 |
|
607 |
-
|
608 |
{
|
609 |
// Have we already included this order in a previous feed?
|
610 |
if ($order->getData(self::ALREADY_SENT_IN_FEED_FLAG) === '1') {
|
@@ -681,7 +681,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
681 |
return true;
|
682 |
}
|
683 |
|
684 |
-
|
685 |
{
|
686 |
$hasOrderCompletelyShipped = true;
|
687 |
$items = $order->getAllItems();
|
@@ -696,7 +696,7 @@ class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abs
|
|
696 |
return $hasOrderCompletelyShipped;
|
697 |
}
|
698 |
|
699 |
-
|
700 |
{
|
701 |
$latestShipmentTimestamp = 0;
|
702 |
|
330 |
* @param Mage_Core_Model_Website $website
|
331 |
* @return int
|
332 |
*/
|
333 |
+
protected function processOrdersForWebsite(Varien_Io_File $ioObject, Mage_Core_Model_Website $website)
|
334 |
{
|
335 |
// Get a collection of all the orders
|
336 |
$orders = Mage::getModel('sales/order')->getCollection();
|
370 |
* @param Mage_Core_Model_Store_Group $group
|
371 |
* @return int
|
372 |
*/
|
373 |
+
protected function processOrdersForGroup(Varien_Io_File $ioObject, Mage_Core_Model_Store_Group $group)
|
374 |
{
|
375 |
// Get a collection of all the orders
|
376 |
$orders = Mage::getModel('sales/order')->getCollection();
|
410 |
* @param Mage_Core_Model_Store $store
|
411 |
* @return int
|
412 |
*/
|
413 |
+
protected function processOrdersForStore(Varien_Io_File $ioObject, Mage_Core_Model_Store $store)
|
414 |
{
|
415 |
// Get a collection of all the orders
|
416 |
$orders = Mage::getModel('sales/order')->getCollection();
|
446 |
* @param $orders
|
447 |
* @return int
|
448 |
*/
|
449 |
+
protected function writeOrdersToFile(Varien_Io_File $ioObject, $orders)
|
450 |
{
|
451 |
// Get ref to BV helper
|
452 |
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
568 |
}
|
569 |
}
|
570 |
|
571 |
+
protected function orderToString(Mage_Sales_Model_Order $order)
|
572 |
{
|
573 |
return "\nOrder {Id: " . $order->getIncrementId()
|
574 |
. "\n\tCustomerId: " . $order->getCustomerId()
|
583 |
. "\n}";
|
584 |
}
|
585 |
|
586 |
+
protected function getTriggeringEventDate(Mage_Sales_Model_Order $order, $triggeringEvent)
|
587 |
{
|
588 |
$timestamp = strtotime($order->getCreatedAtDate());
|
589 |
|
594 |
return date('c', $timestamp);
|
595 |
}
|
596 |
|
597 |
+
protected function getNumDaysLookbackStartDate()
|
598 |
{
|
599 |
return date('Y-m-d', strtotime(date('Y-m-d', time()) . ' -' . self::NUM_DAYS_LOOKBACK . ' days'));
|
600 |
}
|
601 |
|
602 |
+
protected function getDelayDaysThresholdTimestamp($delayDaysSinceEvent)
|
603 |
{
|
604 |
return time() - (24 * 60 * 60 * $delayDaysSinceEvent);
|
605 |
}
|
606 |
|
607 |
+
protected function shouldIncludeOrder(Mage_Sales_Model_Order $order, $triggeringEvent, $delayDaysSinceEvent)
|
608 |
{
|
609 |
// Have we already included this order in a previous feed?
|
610 |
if ($order->getData(self::ALREADY_SENT_IN_FEED_FLAG) === '1') {
|
681 |
return true;
|
682 |
}
|
683 |
|
684 |
+
protected function hasOrderCompletelyShipped(Mage_Sales_Model_Order $order)
|
685 |
{
|
686 |
$hasOrderCompletelyShipped = true;
|
687 |
$items = $order->getAllItems();
|
696 |
return $hasOrderCompletelyShipped;
|
697 |
}
|
698 |
|
699 |
+
protected function getLatestShipmentDate(Mage_Sales_Model_Order $order)
|
700 |
{
|
701 |
$latestShipmentTimestamp = 0;
|
702 |
|
app/code/local/Bazaarvoice/Connector/etc/config.xml
CHANGED
@@ -8,7 +8,7 @@
|
|
8 |
<config>
|
9 |
<modules>
|
10 |
<Bazaarvoice_Connector>
|
11 |
-
<version>6.
|
12 |
<depends>
|
13 |
<!-- no dependencies -->
|
14 |
</depends>
|
8 |
<config>
|
9 |
<modules>
|
10 |
<Bazaarvoice_Connector>
|
11 |
+
<version>6.3.0</version>
|
12 |
<depends>
|
13 |
<!-- no dependencies -->
|
14 |
</depends>
|
lib/Bazaarvoice/BVFooter.php
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* BV PHP SEO SDK Footer
|
5 |
+
*/
|
6 |
+
class BVFooter {
|
7 |
+
const VERSION = '3.1.0';
|
8 |
+
|
9 |
+
private $base;
|
10 |
+
private $url;
|
11 |
+
private $access_method;
|
12 |
+
private $msg;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* BVFooter Class Constructor
|
16 |
+
*
|
17 |
+
* @access public
|
18 |
+
* @param array ($base) - base class parameters
|
19 |
+
* @param string ($url) - SEO url
|
20 |
+
* @param string ($access_method) - access method
|
21 |
+
* @param string ($msg) - build message
|
22 |
+
* @return object
|
23 |
+
*/
|
24 |
+
public function __construct($base, $access_method, $msg) {
|
25 |
+
$this->base = $base;
|
26 |
+
$this->access_method = $access_method;
|
27 |
+
$this->msg = $msg;
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* buildSDKFooter
|
32 |
+
*
|
33 |
+
* Returns hidden SDK footer.
|
34 |
+
*
|
35 |
+
* @access public
|
36 |
+
* @return string Html formatted footer.
|
37 |
+
*/
|
38 |
+
public function buildSDKFooter() {
|
39 |
+
$method_type = !empty($this->base->config['internal_file_path']) ? 'LOCAL' : 'CLOUD';
|
40 |
+
$access_method = $this->access_method;
|
41 |
+
$time_end = microtime(true);
|
42 |
+
|
43 |
+
if (!empty($this->base->start_time)) {
|
44 |
+
$exec_time = round(($time_end - $this->base->start_time) * 1000, 2);
|
45 |
+
} else {
|
46 |
+
$exec_time = 0;
|
47 |
+
}
|
48 |
+
$content_type = mb_strtoupper($this->base->config['content_type']);
|
49 |
+
$subject_type = mb_strtoupper($this->base->config['subject_type']);
|
50 |
+
|
51 |
+
$footer = "\n" . '<ul id="BVSEOSDK_meta" style="display:none !important;">';
|
52 |
+
$footer .= "\n" . ' <li data-bvseo="sdk">bvseo_sdk, p_sdk, ' . self::VERSION . '</li>';
|
53 |
+
$footer .= "\n" . ' <li data-bvseo="sp_mt">' . $method_type . ', ' . $access_method . ', ' . $exec_time . 'ms</li>';
|
54 |
+
$footer .= "\n" . ' <li data-bvseo="ct_st">' . $content_type . ', ' . $subject_type . '</li>';
|
55 |
+
if (!empty($this->msg)) {
|
56 |
+
$footer .= "\n" . ' <li data-bvseo="ms">bvseo-msg: ' . $this->msg . '</li>';
|
57 |
+
}
|
58 |
+
$footer .= "\n" . '</ul>';
|
59 |
+
|
60 |
+
return $footer;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* buildSDKDebugFooter
|
65 |
+
*
|
66 |
+
* Returns hidden SDK debug footer.
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @return string Html formatted debug footer.
|
70 |
+
*/
|
71 |
+
public function buildSDKDebugFooter() {
|
72 |
+
$staging = !empty($this->base->config['staging']) ? 'TRUE' : 'FALSE';
|
73 |
+
$testing = !empty($this->base->config['testing']) ? 'TRUE' : 'FALSE';
|
74 |
+
$sdk_enabled = !empty($this->base->config['seo_sdk_enabled']) ? 'TRUE' : 'FALSE';
|
75 |
+
$ssl_enabled = !empty($this->base->config['ssl_enabled']) ? 'TRUE' : 'FALSE';
|
76 |
+
$proxy_host = !empty($this->base->config['proxy_host']) ? $this->base->config['proxy_host'] : 'none';
|
77 |
+
$proxy_port = !empty($this->base->config['proxy_port']) ? $this->base->config['proxy_port'] : '0';
|
78 |
+
$local_seo_file_root = (!empty($this->base->config['load_seo_files_locally'])) ? $this->base->config['local_seo_file_root'] : 'FALSE';
|
79 |
+
$content_type = mb_strtoupper($this->base->config['content_type']);
|
80 |
+
$subject_type = mb_strtoupper($this->base->config['subject_type']);
|
81 |
+
if (!empty($this->base->config['page_params']['subject_id'])
|
82 |
+
&& !empty($this->base->config['page_params']['content_type'])
|
83 |
+
&& $this->base->config['page_params']['content_type'] == $this->base->config['content_type']) {
|
84 |
+
$subject_id = $this->base->config['page_params']['subject_id'];
|
85 |
+
} else {
|
86 |
+
$subject_id = $this->base->config['subject_id'];
|
87 |
+
}
|
88 |
+
|
89 |
+
$footer = "\n" . '<ul id="BVSEOSDK_DEBUG" style="display:none;">';
|
90 |
+
|
91 |
+
$footer .= "\n" . ' <li data-bvseo="staging">' . $staging . '</li>';
|
92 |
+
$footer .= "\n" . ' <li data-bvseo="testing">' . $testing . '</li>';
|
93 |
+
$footer .= "\n" . ' <li data-bvseo="seo.sdk.enabled">' . $sdk_enabled . '</li>';
|
94 |
+
if (!isset($this->base->config['subject_type']) || $this->base->config['subject_type'] != 'seller') {
|
95 |
+
$footer .= "\n" . ' <li data-bvseo="stagingS3Hostname">' . $this->base->bv_config['seo-domain']['staging'] . '</li>';
|
96 |
+
$footer .= "\n" . ' <li data-bvseo="productionS3Hostname">' . $this->base->bv_config['seo-domain']['production'] . '</li>';
|
97 |
+
$footer .= "\n" . ' <li data-bvseo="testingStagingS3Hostname">' . $this->base->bv_config['seo-domain']['testing_staging'] . '</li>';
|
98 |
+
$footer .= "\n" . ' <li data-bvseo="testingProductionS3Hostname">' . $this->base->bv_config['seo-domain']['testing_production'] . '</li>';
|
99 |
+
}
|
100 |
+
$footer .= "\n" . ' <li data-bvseo="proxyHost">' . $proxy_host . '</li>';
|
101 |
+
$footer .= "\n" . ' <li data-bvseo="proxyPort">' . $proxy_port . '</li>';
|
102 |
+
$footer .= "\n" . ' <li data-bvseo="seo.sdk.execution.timeout.bot">' . $this->base->config['execution_timeout_bot'] . '</li>';
|
103 |
+
$footer .= "\n" . ' <li data-bvseo="seo.sdk.execution.timeout">' . $this->base->config['execution_timeout'] . '</li>';
|
104 |
+
$footer .= "\n" . ' <li data-bvseo="localSEOFileRoot">' . $local_seo_file_root . '</li>';
|
105 |
+
$footer .= "\n" . ' <li data-bvseo="cloudKey">' . $this->base->config['cloud_key'] . '</li>';
|
106 |
+
$footer .= "\n" . ' <li data-bvseo="bv.root.folder">' . $this->base->config['bv_root_folder'] . '</li>';
|
107 |
+
$footer .= "\n" . ' <li data-bvseo="seo.sdk.charset">' . $this->base->config['charset'] . '</li>';
|
108 |
+
$footer .= "\n" . ' <li data-bvseo="seo.sdk.ssl.enabled">' . $ssl_enabled . '</li>';
|
109 |
+
$footer .= "\n" . ' <li data-bvseo="crawlerAgentPattern">' . $this->base->config['crawler_agent_pattern'] . '</li>';
|
110 |
+
$footer .= "\n" . ' <li data-bvseo="subjectID">' . urlencode($subject_id) . '</li>';
|
111 |
+
|
112 |
+
|
113 |
+
$footer .= "\n" . ' <li data-bvseo="en">' . $sdk_enabled . '</li>';
|
114 |
+
$footer .= "\n" . ' <li data-bvseo="pn">bvseo-' . $this->base->config['page'] . '</li>';
|
115 |
+
$footer .= "\n" . ' <li data-bvseo="userAgent">' . $_SERVER['HTTP_USER_AGENT'] . '</li>';
|
116 |
+
$footer .= "\n" . ' <li data-bvseo="pageURI">' . $this->base->config['page_url'] . '</li>';
|
117 |
+
$footer .= "\n" . ' <li data-bvseo="baseURI">' . $this->base->config['base_url'] . '</li>';
|
118 |
+
$footer .= "\n" . ' <li data-bvseo="contentType">' . $content_type . '</li>';
|
119 |
+
$footer .= "\n" . ' <li data-bvseo="subjectType">' . $subject_type . '</li>';
|
120 |
+
if (!empty($this->base->seo_url)) {
|
121 |
+
$footer .= "\n" . ' <li data-bvseo="contentURL">' . $this->base->seo_url . '</li>';
|
122 |
+
}
|
123 |
+
|
124 |
+
$footer .= "\n" . '</ul>';
|
125 |
+
|
126 |
+
return $footer;
|
127 |
+
}
|
128 |
+
|
129 |
+
}
|
lib/Bazaarvoice/BVUtility.php
ADDED
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Tick function for execTimer.
|
5 |
+
*
|
6 |
+
* @param int ($start) - start time in ms
|
7 |
+
* @param int ($exec_time_ms) - execution time in ms
|
8 |
+
* @param bool ($is_bot) - shows the mode in which script was run
|
9 |
+
*/
|
10 |
+
function tick_timer($start, $exec_time, $is_bot) {
|
11 |
+
static $once = true;
|
12 |
+
if ((microtime(1) - $start) > $exec_time) {
|
13 |
+
if ($once) {
|
14 |
+
$once = false;
|
15 |
+
throw new Exception('Execution timed out' . ($is_bot ? ' for search bot' : '') . ', exceeded ' . $exec_time * 1000 . 'ms');
|
16 |
+
}
|
17 |
+
}
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* BV PHP SEO SDK Utilities.
|
22 |
+
*/
|
23 |
+
class BVUtility {
|
24 |
+
public static $supportedContentTypes = array(
|
25 |
+
'r' => 'REVIEWS',
|
26 |
+
'q' => 'QUESTIONS',
|
27 |
+
's' => 'STORIES',
|
28 |
+
'u' => 'UNIVERSAL',
|
29 |
+
'sp'=> 'SPOTLIGHTS'
|
30 |
+
);
|
31 |
+
private static $supportedSubjectTypes = array(
|
32 |
+
'p' => 'PRODUCT',
|
33 |
+
'c' => 'CATEGORY',
|
34 |
+
'e' => 'ENTRY',
|
35 |
+
'd' => 'DETAIL',
|
36 |
+
's' => 'SELLER'
|
37 |
+
);
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Method used to limit execution time of the script.
|
41 |
+
*
|
42 |
+
* @access public
|
43 |
+
* @param int ($exec_time_ms) - execution time in ms
|
44 |
+
* @param bool ($is_bot) - shows the mode in which script was run
|
45 |
+
*/
|
46 |
+
public static function execTimer($exec_time_ms, $is_bot = false, $start = 0) {
|
47 |
+
$exec_time = $exec_time_ms / 1000;
|
48 |
+
declare(ticks = 1); // or more if 1 takes too much time
|
49 |
+
if (empty($start)) {
|
50 |
+
$start = microtime(1);
|
51 |
+
}
|
52 |
+
register_tick_function('tick_timer', $start, $exec_time, $is_bot);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Method used to stop execution time checker.
|
57 |
+
*
|
58 |
+
* @access public
|
59 |
+
*/
|
60 |
+
public static function stopTimer() {
|
61 |
+
unregister_tick_function('tick_timer');
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Parse the provided "bvstate" parameter value.
|
66 |
+
*
|
67 |
+
* @access public
|
68 |
+
* @param string $bvstate - Value of the bvstate parameter.
|
69 |
+
* @return array - parsed "bvstate" parameters.
|
70 |
+
*/
|
71 |
+
public static function getBVStateHash($bvstate) {
|
72 |
+
$bvStateHash = array();
|
73 |
+
$bvp = mb_split("/", $bvstate);
|
74 |
+
foreach ($bvp as $param) {
|
75 |
+
$key = static::mb_trim(mb_substr($param, 0, mb_strpos($param, ':')));
|
76 |
+
$bvStateHash[$key] = static::mb_trim(mb_substr($param, mb_strpos($param, ':') + 1));
|
77 |
+
}
|
78 |
+
return $bvStateHash;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Checks content type or subject type is supported.
|
83 |
+
* If type is not supported throw exception.
|
84 |
+
*
|
85 |
+
* @access public
|
86 |
+
* @param string ($type) - content type or subject type which have to be checked.
|
87 |
+
* @param string ($typeType) - default 'ct', mark of type 'ct' - content type, 'st' - subject type
|
88 |
+
* @return boolean True if type is correct and no exception was thrown.
|
89 |
+
*/
|
90 |
+
public static function checkType($type, $typeType = 'ct') {
|
91 |
+
if ($typeType == 'st') {
|
92 |
+
$typeName = 'subject type';
|
93 |
+
$typeArray = static::$supportedSubjectTypes;
|
94 |
+
} else {
|
95 |
+
$typeName = 'content type';
|
96 |
+
$typeArray = static::$supportedContentTypes;
|
97 |
+
}
|
98 |
+
if (!array_key_exists(mb_strtolower($type), $typeArray)) {
|
99 |
+
foreach ($typeArray as $key => $value) {
|
100 |
+
$supportList[] = $key . '=' . $value;
|
101 |
+
}
|
102 |
+
throw new Exception('Obtained not supported ' . $typeName
|
103 |
+
. '. BV Class supports following ' . $typeName . ': '
|
104 |
+
. implode(', ', $supportList));
|
105 |
+
}
|
106 |
+
|
107 |
+
return true;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Generates an array of parameters from the bvstate parameter value.
|
112 |
+
*
|
113 |
+
* @access public
|
114 |
+
* @param string $bvstate - "bvstate" parameter value.
|
115 |
+
* @return array - array of parameters that are ready to use in script.
|
116 |
+
*/
|
117 |
+
public static function getBVStateParams($bvstate) {
|
118 |
+
$bvStateHash = self::getBVStateHash($bvstate);
|
119 |
+
$params = array();
|
120 |
+
|
121 |
+
// If the content type 'ct' parameter is not present, then ignore bvstate.
|
122 |
+
if (empty($bvStateHash['ct'])) {
|
123 |
+
return $params;
|
124 |
+
}
|
125 |
+
|
126 |
+
if (!empty($bvStateHash)) {
|
127 |
+
if (!empty($bvStateHash['id'])) {
|
128 |
+
$params['subject_id'] = $bvStateHash['id'];
|
129 |
+
}
|
130 |
+
if (!empty($bvStateHash['pg'])) {
|
131 |
+
$params['page'] = $bvStateHash['pg'];
|
132 |
+
}
|
133 |
+
if (!empty($bvStateHash['ct'])) {
|
134 |
+
$cType = $bvStateHash['ct'];
|
135 |
+
self::checkType($cType, 'ct');
|
136 |
+
$params['content_type'] = mb_strtolower(self::$supportedContentTypes[$cType]);
|
137 |
+
}
|
138 |
+
if (!empty($bvStateHash['st'])) {
|
139 |
+
$sType = $bvStateHash['st'];
|
140 |
+
self::checkType($sType, 'st');
|
141 |
+
$params['subject_type'] = mb_strtolower(self::$supportedSubjectTypes[$sType]);
|
142 |
+
}
|
143 |
+
if (!empty($bvStateHash['reveal'])) {
|
144 |
+
$params['bvreveal'] = $bvStateHash['reveal'];
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
if (!empty($params)) {
|
149 |
+
// This acts as a flag to tell us that a useful bvstate value was in fact
|
150 |
+
// extracted from the URL.
|
151 |
+
$params['base_url_bvstate'] = TRUE;
|
152 |
+
}
|
153 |
+
if (empty($params['page'])) {
|
154 |
+
$params['page'] = '1';
|
155 |
+
}
|
156 |
+
|
157 |
+
return $params;
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Parse name=value parameters from the URL query string, fragment, and
|
162 |
+
* _escaped_fragment_.
|
163 |
+
*
|
164 |
+
* @access public
|
165 |
+
* @param string ($url) - The URL.
|
166 |
+
* @return array - An array of parameters values indexed by parameter names.
|
167 |
+
*/
|
168 |
+
public static function parseUrlParameters($url) {
|
169 |
+
// Why are we doing things in this devious way? The answer is to be as
|
170 |
+
// multibyte-supportive as possible. Most of the URL-parsing tools in the
|
171 |
+
// toolbox appear to be only varying degrees of multibyte-supportive; good
|
172 |
+
// for UTF-8 but not so great if you venture beyond that.
|
173 |
+
|
174 |
+
// Break down the URL into a mix of things, some of which are name=value
|
175 |
+
// pairs.
|
176 |
+
$params = array();
|
177 |
+
$chunks = mb_split('\?|&|&|#!|#|_escaped_fragment_=|%26', $url);
|
178 |
+
foreach ($chunks as $chunk) {
|
179 |
+
// If this is name=value, then there will be two items.
|
180 |
+
$values = mb_split('=', $chunk);
|
181 |
+
if (sizeof($values) == 2) {
|
182 |
+
// Since we're moving left to right in the URL, and we want query string
|
183 |
+
// to win over fragment if there are the same parameters in both, then
|
184 |
+
// only add if not already there.
|
185 |
+
if (!isset($params[$values[0]])) {
|
186 |
+
$params[$values[0]] = $values[1];
|
187 |
+
}
|
188 |
+
}
|
189 |
+
}
|
190 |
+
return $params;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Remove a parameter from the provided URL.
|
195 |
+
*
|
196 |
+
* This will remove the named parameter wherever it occurs as name=value in
|
197 |
+
* the URL via a simple regex replacement. This is crude but the most
|
198 |
+
* straightforward way of going about this in PHP.
|
199 |
+
*
|
200 |
+
* If there is a query string delimeter following the name=value parameter
|
201 |
+
* then that will also be removed.
|
202 |
+
*
|
203 |
+
* E.g. we're expecting to remove the bvstate from URLs such as:
|
204 |
+
*
|
205 |
+
* http://example.com/product/123?bvstate=pg:4/ct:r
|
206 |
+
* http://example.com/product/123#!bvstate=pg:4/ct:r
|
207 |
+
*
|
208 |
+
* This will only be used for Bazaarvoice SEO parameters, so apologies in
|
209 |
+
* advance to the one person in the universe for whom bvstate=xyz is a vital
|
210 |
+
* part of the URL path.
|
211 |
+
*
|
212 |
+
* Note that the fragment isn't passed to the server, so we're not really
|
213 |
+
* going to see that in practice. Attention is given to that here for the
|
214 |
+
* sake of completeness.
|
215 |
+
*
|
216 |
+
* @access public
|
217 |
+
* @param string ($url) - The URL.
|
218 |
+
* @param string ($paramName) - Name of the parameter to be removed.
|
219 |
+
* @return string - The updated URL.
|
220 |
+
*/
|
221 |
+
public static function removeUrlParam($url, $paramName) {
|
222 |
+
// The ereg POSIX regex functions are all greedy all the time, which makes
|
223 |
+
// this harder than it has to be.
|
224 |
+
//
|
225 |
+
// Big assumption: our seo link values will never contain the % character.
|
226 |
+
//
|
227 |
+
// http://example.com/product/123?bvstate=pg:4/ct:r&a=b
|
228 |
+
$url = mb_ereg_replace($paramName . '=[^&#%]*&', '', $url);
|
229 |
+
// http://example.com/product/123?bvstate=pg:4/ct:r&a=b
|
230 |
+
// http://example.com/product/123?#!bvstate=pg:4/ct:r&a=b
|
231 |
+
// http://example.com/product/123?_escaped_fragment_=bvstate=pg:4/ct:r%26a=b
|
232 |
+
$url = mb_ereg_replace($paramName . '=[^&#%]*(&|%26)', '', $url);
|
233 |
+
// http://example.com/product/123?bvstate=pg:4/ct:r#!x/y/z
|
234 |
+
$url = mb_ereg_replace($paramName . '=[^&#]*#', '#', $url);
|
235 |
+
// This one last as it will break everything if we haven't already dealt
|
236 |
+
// with all of the cases, since .* is always greedy in POSIX regex.
|
237 |
+
// http://example.com/product/123?bvstate=pg:4/ct:r
|
238 |
+
$url = mb_ereg_replace($paramName . '=[^&#%]*$', '', $url);
|
239 |
+
return $url;
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* A multibyte-safe trim.
|
244 |
+
* (http://stackoverflow.com/questions/10066647/multibyte-trim-in-php/10067670#10067670)
|
245 |
+
*
|
246 |
+
* @access public
|
247 |
+
* @param string ($str) - The string that will be trimmed.
|
248 |
+
* @return string - The trimmed string.
|
249 |
+
*/
|
250 |
+
public static function mb_trim($str) {
|
251 |
+
return mb_ereg_replace('(^\s+)|(\s+$)', '', $str);
|
252 |
+
}
|
253 |
+
|
254 |
+
}
|
lib/Bazaarvoice/bvseosdk.php
CHANGED
@@ -3,609 +3,1039 @@
|
|
3 |
/**
|
4 |
* BV PHP SEO SDK
|
5 |
*
|
6 |
-
* Base code to power either SEO or SEO and display. This SDK
|
7 |
-
* is provided as is and Bazaarvoice, Inc. is not
|
8 |
-
* for future
|
9 |
-
* this SDK as needed to suit your needs.
|
10 |
*
|
11 |
* This SDK was built with the following assumptions:
|
12 |
-
*
|
13 |
-
*
|
14 |
-
*
|
15 |
-
*
|
16 |
-
*
|
17 |
*
|
18 |
*/
|
19 |
-
|
20 |
/**
|
21 |
* Example usage:
|
22 |
*
|
23 |
* require(bvsdk.php);
|
24 |
*
|
25 |
* $bv = new BV(array(
|
26 |
-
*
|
27 |
-
*
|
28 |
-
*
|
29 |
-
*
|
30 |
* ));
|
31 |
-
*
|
32 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
// ------------------------------------------------------------------------
|
35 |
|
36 |
/**
|
37 |
* BV Class
|
38 |
-
*
|
39 |
-
* When you instantiate the BV class, pass it's constructor an array
|
40 |
-
* containing the following key value pairs.
|
41 |
-
*
|
42 |
* Required fields:
|
43 |
-
*
|
44 |
-
*
|
45 |
-
*
|
46 |
*
|
47 |
* Optional fields
|
48 |
-
*
|
49 |
-
*
|
50 |
-
*
|
51 |
-
*
|
52 |
-
*
|
53 |
-
*
|
|
|
|
|
|
|
|
|
|
|
54 |
*/
|
55 |
-
|
56 |
class BV {
|
57 |
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
'base_page_url' => $this->_getCurrentUrl(),
|
84 |
-
'bot_detection' => FALSE, // bot detection should only be enabled if average execution time regularly exceeds 350ms.
|
85 |
-
'include_display_integration_code' => FALSE,
|
86 |
-
'client_name' => $params['deployment_zone_id'],
|
87 |
-
'internal_file_path' => FALSE,
|
88 |
-
'bot_list' => 'msnbot|google|teoma|bingbot|yandexbot|yahoo', // used in regex to determine if request is a bot or not
|
89 |
|
|
|
|
|
|
|
|
|
|
|
90 |
);
|
|
|
91 |
|
92 |
-
|
93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
-
|
99 |
-
$this->questions = new Questions($this->config);
|
100 |
-
|
101 |
-
// setup the timer object
|
102 |
|
103 |
-
|
104 |
|
105 |
-
|
106 |
-
// included in the BV class.
|
107 |
-
public function _getCurrentUrl(){
|
108 |
-
// depending on protocal set the
|
109 |
-
// beginging of url and defualt port
|
110 |
-
if(isset($_SERVER["HTTPS"])){
|
111 |
-
$url = 'https://';
|
112 |
-
$defaultPort = '443';
|
113 |
-
}else{
|
114 |
-
$url = 'http://';
|
115 |
-
$defaultPort = '80';
|
116 |
-
}
|
117 |
|
118 |
-
|
|
|
|
|
|
|
|
|
119 |
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
|
|
|
|
|
|
|
|
|
|
126 |
|
127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
}
|
129 |
-
} // end of BV class
|
130 |
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
|
|
|
|
135 |
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
{
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
if ($this->_isBot())
|
167 |
-
{
|
168 |
-
|
169 |
-
|
170 |
-
// get the page number of SEO content to load
|
171 |
-
$page_number = $this->_getPageNumber();
|
172 |
-
|
173 |
-
// build the URL to access the SEO content for
|
174 |
-
// this product / page combination
|
175 |
-
$seo_url = $this->_buildSeoUrl($page_number);
|
176 |
-
|
177 |
-
// make call to get SEO payload from cloud
|
178 |
-
$seo_content = $this->_fetchSeoContent($seo_url);
|
179 |
-
|
180 |
-
// replace tokens for pagination URLs with page_url
|
181 |
-
$seo_content = $this->_replaceTokens($seo_content);
|
182 |
-
|
183 |
-
// if debug mode is on we want to include more debug data
|
184 |
-
//if (isset($_GET['bvreveal']))
|
185 |
-
//{
|
186 |
-
// if($_GET['bvreveal'] == 'debug')
|
187 |
-
// {
|
188 |
-
// $printable_config = $this->config;
|
189 |
-
// $seo_content .= $this->_buildComment('Config options: '.print_r($printable_config, TRUE));
|
190 |
-
// }
|
191 |
-
//}
|
192 |
-
|
193 |
-
$pay_load = $page_number;
|
194 |
-
$pay_load = $seo_content;
|
195 |
-
}
|
196 |
-
else
|
197 |
-
{
|
198 |
-
$pay_load = $this->_buildComment('JavaScript-only Display','');
|
199 |
-
}
|
200 |
|
201 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
}
|
203 |
|
|
|
204 |
|
205 |
-
|
206 |
-
|
207 |
-
//--------------------------------------------------------------------
|
208 |
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
* @access private
|
216 |
-
* @return bool
|
217 |
-
*/
|
218 |
|
219 |
-
|
220 |
-
|
221 |
-
// we need to check the user agent string to see if this is a bot,
|
222 |
-
// unless the bvreveal parameter is there or we have disabled bot
|
223 |
-
// detection through the bot_detection flag
|
224 |
-
if(isset($_GET['bvreveal']) OR ! $this->config['bot_detection']){
|
225 |
-
return TRUE;
|
226 |
-
}
|
227 |
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
/**
|
233 |
-
* getPageNumber
|
234 |
-
*
|
235 |
-
* Helper method to pull from the URL the page of SEO we need to view.
|
236 |
-
*
|
237 |
-
* @access private
|
238 |
-
* @return int
|
239 |
-
*/
|
240 |
-
private function _getPageNumber()
|
241 |
-
{
|
242 |
-
// default to page 1 if a page is not specified in the URL
|
243 |
-
$page_number = 1;
|
244 |
-
|
245 |
-
//parse the current url that's passed in via the parameters
|
246 |
-
$currentUrlArray = parse_url($this->config['current_page_url']);
|
247 |
-
|
248 |
-
$query = $currentUrlArray['path']; //get the path out of the parsed url array
|
249 |
-
|
250 |
-
parse_str($query, $bvcurrentpagedata); //parse the sub url such that you get the important part...page number
|
251 |
-
|
252 |
-
// bvpage is not currently implemented
|
253 |
-
if (isset($_GET['bvpage']) ){
|
254 |
-
$page_number = (int) $_GET['bvpage'];
|
255 |
-
|
256 |
-
// remove the bvpage parameter from the base URL so we don't keep appending it
|
257 |
-
$seo_param = str_replace('/', '\/', $_GET['bvrrp']); // need to escape slashses for regex
|
258 |
-
$this->config['base_page_url'] = preg_replace('/[?&]bvrrp='.$seo_param.'/', '', $this->config['base_page_url']);
|
259 |
-
}
|
260 |
-
// other implementations use the bvrrp, bvqap, or bvsyp parameter ?bvrrp=1234-en_us/reviews/product/2/ASF234.htm
|
261 |
-
else if(isset($_GET['bvrrp']) OR isset($_GET['bvqap']) OR isset($_GET['bvsyp']) ){
|
262 |
-
if(isset($_GET['bvrrp']))
|
263 |
-
{
|
264 |
-
$bvparam = $_GET['bvrrp'];
|
265 |
-
}
|
266 |
-
else if(isset($_GET['bvqap']))
|
267 |
-
{
|
268 |
-
$bvparam = $_GET['bvqap'];
|
269 |
-
}
|
270 |
-
else
|
271 |
-
{
|
272 |
-
$bvparam = $_GET['bvsyp'];
|
273 |
-
}
|
274 |
-
}
|
275 |
-
else if(isset($bvcurrentpagedata)) //if the base url doesn't include the page number information and the current url
|
276 |
-
//is defined then use the data from the current URL.
|
277 |
-
{
|
278 |
-
|
279 |
-
if (isset($bvcurrentpagedata['bvpage']) )
|
280 |
-
{
|
281 |
-
$page_number = (int) $bvcurrentpagedata['bvpage'];
|
282 |
-
$bvparam=$bvcurrentpagedata['bvpage'];
|
283 |
-
// remove the bvpage parameter from the base URL so we don't keep appending it
|
284 |
-
$seo_param = str_replace('/', '\/', $_GET['bvrrp']); // need to escape slashses for regex
|
285 |
-
$this->config['base_page_url'] = preg_replace('/[?&]bvrrp='.$seo_param.'/', '', $this->config['base_page_url']);
|
286 |
-
}
|
287 |
-
// other implementations use the bvrrp, bvqap, or bvsyp parameter ?bvrrp=1234-en_us/reviews/product/2/ASF234.htm
|
288 |
-
else if(isset($bvcurrentpagedata['bvrrp'])
|
289 |
-
|| isset($bvcurrentpagedata['bvqap'])
|
290 |
-
|| isset($bvcurrentpagedata['bvsyp']) )
|
291 |
-
{
|
292 |
-
if(isset($bvcurrentpagedata['bvrrp']))
|
293 |
-
{
|
294 |
-
$bvparam = $bvcurrentpagedata['bvrrp'];
|
295 |
-
}
|
296 |
-
else if(isset($bvcurrentpagedata['bvqap']))
|
297 |
-
{
|
298 |
-
$bvparam = $bvcurrentpagedata['bvqap'];
|
299 |
-
}
|
300 |
-
else
|
301 |
-
{
|
302 |
-
$bvparam = $bvcurrentpagedata['bvsyp'];
|
303 |
-
}
|
304 |
-
}
|
305 |
-
}
|
306 |
-
|
307 |
-
if(isset($bvparam)){
|
308 |
-
preg_match('/\/(\d+?)\/[^\/]+$/', $bvparam, $page_number);
|
309 |
-
$page_number = max(1, (int) $page_number[1]);
|
310 |
-
|
311 |
-
// remove the bvrrp parameter from the base URL so we don't keep appending it
|
312 |
-
$seo_param = str_replace('/', '\/', $bvparam); // need to escape slashses for regex
|
313 |
-
$this->config['base_page_url'] = preg_replace('/[?&]bvrrp='.$seo_param.'/', '', $this->config['base_page_url']);
|
314 |
-
}
|
315 |
-
return $page_number;
|
316 |
-
}// end of _getPageNumber()
|
317 |
-
|
318 |
-
/**
|
319 |
-
* buildSeoUrl
|
320 |
-
*
|
321 |
-
* Helper method to that builds the URL to the SEO payload
|
322 |
-
*
|
323 |
-
* @access private
|
324 |
-
* @param int (page number)
|
325 |
-
* @return string
|
326 |
-
*/
|
327 |
-
private function _buildSeoUrl($page_number){
|
328 |
-
// are we pointing at staging or production?
|
329 |
-
if($this->config['staging']){
|
330 |
-
$hostname = $this->bv_config['seo-domain']['staging'];
|
331 |
-
}else{
|
332 |
-
$hostname = $this->bv_config['seo-domain']['production'];
|
333 |
-
}
|
334 |
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
$this->config['cloud_key'],
|
339 |
-
$this->config['deployment_zone_id'],
|
340 |
-
$this->config['bv_product'],
|
341 |
-
$this->config['subject_type'],
|
342 |
-
$page_number,
|
343 |
-
urlencode($this->config['product_id']).'.htm'
|
344 |
-
);
|
345 |
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
|
354 |
-
|
355 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
356 |
|
357 |
-
|
358 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
359 |
}
|
360 |
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
return $this->_fetchFileContent($resource);
|
366 |
-
}
|
367 |
-
else
|
368 |
-
{
|
369 |
-
return $this->_fetchCloudContent($resource);
|
370 |
-
}
|
371 |
}
|
372 |
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
// return '<!-- curl library is not installed -->';
|
403 |
-
// }
|
404 |
-
|
405 |
-
// create a new cURL resource handle
|
406 |
-
$ch = curl_init();
|
407 |
-
|
408 |
-
curl_setopt($ch, CURLOPT_URL, $url); // Set URL to download
|
409 |
-
curl_setopt($ch, CURLOPT_REFERER, $this->config['current_page_url']); // Set a referer as coming from the current page url
|
410 |
-
curl_setopt($ch, CURLOPT_HEADER, 0); // Include header in result? (0 = yes, 1 = no)
|
411 |
-
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Should cURL return or print out the data? (true = return, false = print)
|
412 |
-
curl_setopt($ch, CURLOPT_TIMEOUT, ($this->config['latency_timeout'] / 1000)); // Timeout in seconds
|
413 |
-
|
414 |
-
// make the request to the given URL and then store the response, request info, and error number
|
415 |
-
// so we can use them later
|
416 |
-
$request = array(
|
417 |
-
'response' => curl_exec($ch),
|
418 |
-
'info' => curl_getinfo($ch),
|
419 |
-
'error_number' => curl_errno($ch),
|
420 |
-
'error_message' => curl_error($ch)
|
421 |
-
);
|
422 |
|
423 |
-
|
424 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
425 |
|
426 |
-
|
|
|
|
|
|
|
|
|
427 |
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
|
|
433 |
|
434 |
-
|
435 |
-
|
436 |
-
$msg = 'HTTP status code of '.$request['info']['http_code'].' was returned';
|
437 |
-
return $this->_buildComment($msg,$url);
|
438 |
-
}
|
439 |
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
465 |
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
$footer .= "\n".' <li id="st">bvseo-'.strtoupper($this->config['subject_type']).'</li>';
|
484 |
-
$footer .= "\n".' <li id="am">bvseo-getContent</li>';
|
485 |
-
if (strlen($msg) > 0) {
|
486 |
-
$footer .= "\n".' <li id="ms">bvseo-msg: '.$msg.'</li>';
|
487 |
-
}
|
488 |
-
$footer .= "\n".'</ul>';
|
489 |
-
|
490 |
-
//when in debug mode, also display the following information
|
491 |
-
if (isset($_GET['bvreveal'])){
|
492 |
-
if($_GET['bvreveal'] == 'debug') {
|
493 |
-
$footer .= "\n".'<ul id="BVSEOSDK_DEBUG" style="display:none;">';
|
494 |
-
$footer .= "\n".' <li id="cloudKey">'.$this->config['cloud_key'].'</li>';
|
495 |
-
$footer .= "\n".' <li id="bv.root.folder">'.$this->config['deployment_zone_id'].'</li>';
|
496 |
-
$footer .= "\n".' <li id="stagingS3Hostname">'.$this->bv_config['seo-domain']['staging'].'</li>';
|
497 |
-
$footer .= "\n".' <li id="productionS3Hostname">'.$this->bv_config['seo-domain']['production'].'</li>';
|
498 |
-
$staging = ($this->config['staging']) ? 'TRUE' : 'FALSE';
|
499 |
-
$footer .= "\n".' <li id="staging">'.$staging.'</li>';
|
500 |
-
$footer .= "\n".' <li id="seo.sdk.execution.timeout">'.$this->config['latency_timeout'].'</li>';
|
501 |
-
$bot_detection = ($this->config['bot_detection']) ? 'TRUE' : 'FALSE';
|
502 |
-
$footer .= "\n".' <li id="botDetection">'.$bot_detection.'</li>';
|
503 |
-
$footer .= "\n".' <li id="crawlerAgentPattern">'.$this->config['bot_list'].'</li>';
|
504 |
-
$footer .= "\n".' <li id="userAgent">'.$_SERVER['HTTP_USER_AGENT'].'</li>';
|
505 |
-
$footer .= "\n".' <li id="pageURI">'.$this->config['current_page_url'].'</li>';
|
506 |
-
$footer .= "\n".' <li id="baseURI">'.$this->config['base_page_url'].'</li>';
|
507 |
-
$footer .= "\n".' <li id="subjectID">'.urlencode($this->config['product_id']).'</li>';
|
508 |
-
$footer .= "\n".' <li id="contentType">'.strtoupper($this->config['bv_product']).'</li>';
|
509 |
-
$footer .= "\n".' <li id="subjectType">'.strtoupper($this->config['subject_type']).'</li>';
|
510 |
-
$footer .= "\n".' <li id="contentURL">'.$url.'</li>';
|
511 |
-
$footer .= "\n".'</ul>';
|
512 |
-
}
|
513 |
-
}
|
514 |
|
515 |
-
|
516 |
-
|
|
|
|
|
|
|
517 |
}
|
518 |
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
527 |
|
528 |
-
|
|
|
|
|
529 |
|
|
|
|
|
|
|
530 |
|
531 |
-
|
|
|
532 |
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
// we need to set the bv_product config
|
540 |
-
// to reviews so we get reviews in our
|
541 |
-
// SEO request
|
542 |
-
$this->config['bv_product'] = 'reviews';
|
543 |
|
544 |
-
|
545 |
-
|
546 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
548 |
|
549 |
-
|
550 |
-
|
551 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
552 |
|
553 |
-
|
554 |
-
|
555 |
-
// regardless of if it's a bot or not
|
556 |
-
if($this->config['include_display_integration_code'])
|
557 |
-
{
|
558 |
-
$pay_load .= '
|
559 |
-
<script>
|
560 |
-
$BV.ui("rr", "show_reviews", {
|
561 |
-
productId: "'.$this->config['product_id'].'"
|
562 |
-
});
|
563 |
-
</script>
|
564 |
-
';
|
565 |
-
}
|
566 |
|
567 |
-
|
|
|
568 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
569 |
}
|
570 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
571 |
|
|
|
|
|
572 |
|
573 |
-
class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
574 |
|
575 |
-
function __construct($params = array())
|
576 |
-
{
|
577 |
// call Base Class constructor
|
578 |
parent::__construct($params);
|
579 |
-
|
580 |
-
// since we are in the
|
581 |
-
// we need to set the
|
582 |
-
// to
|
583 |
// SEO request
|
584 |
-
$this->config['
|
585 |
-
}
|
586 |
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
|
591 |
-
|
592 |
-
// then we need to include the JS integration code
|
593 |
-
// regardless of if it's a bot or not
|
594 |
-
if($this->config['include_display_integration_code'])
|
595 |
-
{
|
596 |
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
productId: "'.$this->config['product_id'].'"
|
601 |
-
});
|
602 |
-
</script>
|
603 |
-
';
|
604 |
-
}
|
605 |
|
606 |
-
|
|
|
607 |
|
608 |
-
}
|
609 |
-
} // end of Questions class
|
610 |
|
611 |
-
// end of
|
3 |
/**
|
4 |
* BV PHP SEO SDK
|
5 |
*
|
6 |
+
* Base code to power either SEO or SEO and display. This SDK
|
7 |
+
* is provided as is and Bazaarvoice, Inc. is not responsible
|
8 |
+
* for future maintenance or support. You are free to modify
|
9 |
+
* this SDK as needed to suit your needs.
|
10 |
*
|
11 |
* This SDK was built with the following assumptions:
|
12 |
+
* - you are running PHP 5 or greater
|
13 |
+
* - you have the curl library installed
|
14 |
+
* - every request has the user agent header
|
15 |
+
* in it (if using a CDN like Akamai additional configuration
|
16 |
+
* maybe required).
|
17 |
*
|
18 |
*/
|
|
|
19 |
/**
|
20 |
* Example usage:
|
21 |
*
|
22 |
* require(bvsdk.php);
|
23 |
*
|
24 |
* $bv = new BV(array(
|
25 |
+
* 'bv_root_folder' => '1234-en_US',
|
26 |
+
* 'subject_id' => 'XXYYY',
|
27 |
+
* 'cloud_key' => 'company-cdfa682b84bef44672efed074093ccd3',
|
28 |
+
* 'staging' => FALSE
|
29 |
* ));
|
30 |
+
*
|
31 |
*/
|
32 |
+
require_once 'BVUtility.php';
|
33 |
+
require_once 'BVFooter.php';
|
34 |
+
|
35 |
+
// Should be declared in file where execTimer will be used.
|
36 |
+
// If declared in the another file it does not affect the current file.
|
37 |
+
declare(ticks = 1);
|
38 |
+
|
39 |
+
// Default charset will be used in case charset parameter is not properly configured by user.
|
40 |
+
define('DEFAULT_CHARSET', 'UTF-8');
|
41 |
|
42 |
// ------------------------------------------------------------------------
|
43 |
|
44 |
/**
|
45 |
* BV Class
|
46 |
+
*
|
47 |
+
* When you instantiate the BV class, pass it's constructor an array
|
48 |
+
* containing the following key value pairs.
|
49 |
+
*
|
50 |
* Required fields:
|
51 |
+
* bv_root_folder (string)
|
52 |
+
* subject_id (string)
|
53 |
+
* cloud_key (string)
|
54 |
*
|
55 |
* Optional fields
|
56 |
+
* base_url (string) (defaults to detecting the base_url automatically)
|
57 |
+
* page_url (string) (defaults to empty, to provide query parameters )
|
58 |
+
* staging (boolean) (defaults to false, need to put true for testing with staging data)
|
59 |
+
* testing (boolean) (defaults to false, need to put true for testing with testing data)
|
60 |
+
* content_type (string) (defaults to reviews, you can pass content type here if needed)
|
61 |
+
* subject_type (string) (defaults to product, you can pass subject type here if needed)
|
62 |
+
* content_sub_type (string) (defaults to stories, for stories you can pass either STORIES_LIST or STORIES_GRID content type)
|
63 |
+
* execution_timeout (int) (in milliseconds) (defaults to 500ms, to set period of time before the BVSEO injection times out for user agents that do not match the criteria set in CRAWLER_AGENT_PATTERN)
|
64 |
+
* execution_timeout_bot (int) (in milliseconds) (defaults to 2000ms, to set period of time before the BVSEO injection times out for user agents that match the criteria set in CRAWLER_AGENT_PATTERN)
|
65 |
+
* charset (string) (defaults to UTF-8, to set alternate character for SDK output)
|
66 |
+
* crawler_agent_pattern (string) (defaults to msnbot|googlebot|teoma|bingbot|yandexbot|yahoo)
|
67 |
*/
|
|
|
68 |
class BV {
|
69 |
|
70 |
+
/**
|
71 |
+
* BV Class Constructor
|
72 |
+
*
|
73 |
+
* The constructor takes in all the arguments via a single array.
|
74 |
+
*
|
75 |
+
* @access public
|
76 |
+
* @param array
|
77 |
+
* @return object
|
78 |
+
*/
|
79 |
+
public function __construct($params = array()) {
|
80 |
+
|
81 |
+
$this->validateParameters($params);
|
82 |
+
|
83 |
+
// config array, defaults are defined here.
|
84 |
+
$this->config = array(
|
85 |
+
'staging' => FALSE,
|
86 |
+
'testing' => FALSE,
|
87 |
+
'content_type' => isset($params['content_type']) ? $params['content_type'] : 'reviews',
|
88 |
+
'subject_type' => isset($params['subject_type']) ? $params['subject_type'] : 'product',
|
89 |
+
'page_url' => isset($params['page_url']) ? $params['page_url'] : '',
|
90 |
+
'base_url' => isset($params['base_url']) ? $params['base_url'] : '',
|
91 |
+
'include_display_integration_code' => FALSE,
|
92 |
+
'client_name' => $params['bv_root_folder'],
|
93 |
+
'local_seo_file_root' => '',
|
94 |
+
'load_seo_files_locally' => FALSE,
|
95 |
+
// used in regex to determine if request is a bot or not
|
96 |
+
'crawler_agent_pattern' => 'msnbot|google|teoma|bingbot|yandexbot|yahoo',
|
97 |
+
'ssl_enabled' => FALSE,
|
98 |
+
'proxy_host' => '',
|
99 |
+
'proxy_port' => '',
|
100 |
+
'charset' => 'UTF-8',
|
101 |
+
'seo_sdk_enabled' => TRUE,
|
102 |
+
'execution_timeout' => 500,
|
103 |
+
'execution_timeout_bot' => 2000,
|
104 |
+
'bvreveal' => isset($params['bvreveal']) ? $params['bvreveal'] : '',
|
105 |
+
'page' => 1,
|
106 |
+
'page_params' => array()
|
107 |
+
);
|
108 |
+
|
109 |
+
// Merge passed in params with defaults for config.
|
110 |
+
$this->config = array_merge($this->config, $params);
|
111 |
+
|
112 |
+
// Obtain all the name=value parameters from either the page URL passed in,
|
113 |
+
// or from the actual page URL as seen by PHP. Parameter values from the
|
114 |
+
// actual URL override those from the URL passed in, as that is usually a
|
115 |
+
// trucated URL where present at all.
|
116 |
+
//
|
117 |
+
// Note that we're taking parameters from query string, fragment, or
|
118 |
+
// _escaped_fragment_. (Though fragment is not passed to the server, so
|
119 |
+
// we won't actually see that in practice).
|
120 |
+
//
|
121 |
+
// We're after bvrrp, bvqap, bvsyp, and bvstate, but sweep up everything
|
122 |
+
// while we're here.
|
123 |
+
if (isset($params['page_url'])) {
|
124 |
+
$this->config['bv_page_data'] = BVUtility::parseUrlParameters($params['page_url']);
|
125 |
+
}
|
126 |
+
|
127 |
+
// Extract bvstate if present and parse that into a set of useful values.
|
128 |
+
if (isset($this->config['bv_page_data']['bvstate'])) {
|
129 |
+
$this->config['page_params'] = BVUtility::getBVStateParams($this->config['bv_page_data']['bvstate']);
|
130 |
+
}
|
131 |
+
|
132 |
+
// Remove any trailing URL delimeters from the base URL. E.g.:
|
133 |
+
// http://example.com?
|
134 |
+
// http://example.com?a=b&
|
135 |
+
// http://example.com?a=b&_escaped_fragment_=x/y/z?r=s%26
|
136 |
+
//
|
137 |
+
$this->config['base_url'] = mb_ereg_replace('(&|\?|%26)$', '', $this->config['base_url']);
|
138 |
+
|
139 |
+
// Get rid of all the other things we care about from the base URL, so that
|
140 |
+
// we don't double up the parameters.
|
141 |
+
$this->config['base_url'] = BVUtility::removeUrlParam($this->config['base_url'], 'bvstate');
|
142 |
+
$this->config['base_url'] = BVUtility::removeUrlParam($this->config['base_url'], 'bvrrp');
|
143 |
+
$this->config['base_url'] = BVUtility::removeUrlParam($this->config['base_url'], 'bvqap');
|
144 |
+
$this->config['base_url'] = BVUtility::removeUrlParam($this->config['base_url'], 'bvsyp');
|
145 |
+
|
146 |
+
// Create the processor objects.
|
147 |
+
$this->reviews = new Reviews($this->config);
|
148 |
+
$this->questions = new Questions($this->config);
|
149 |
+
$this->stories = new Stories($this->config);
|
150 |
+
$this->spotlights = new Spotlights($this->config);
|
151 |
+
$this->sellerratings = new SellerRatings($this->config);
|
152 |
+
|
153 |
+
// Assign one to $this->SEO based on the content type.
|
154 |
+
$ct = isset($this->config['page_params']['content_type']) ? $this->config['page_params']['content_type'] : $this->config['content_type'];
|
155 |
+
if (isset($ct)) {
|
156 |
+
switch ($ct) {
|
157 |
+
case 'reviews': {
|
158 |
+
$st = isset($this->config['page_params']['subject_type']) ? $this->config['page_params']['subject_type'] : $this->config['subject_type'];
|
159 |
+
if (isset($st) && $st == 'seller') {
|
160 |
+
$this->SEO = $this->sellerratings;
|
161 |
+
} else {
|
162 |
+
$this->SEO = $this->reviews;
|
163 |
+
}
|
164 |
+
break;
|
165 |
}
|
166 |
+
case 'questions': $this->SEO = $this->questions;
|
167 |
+
break;
|
168 |
+
case 'stories': $this->SEO = $this->stories;
|
169 |
+
break;
|
170 |
+
case 'spotlights': $this->SEO = $this->spotlights;
|
171 |
+
break;
|
172 |
+
default:
|
173 |
+
throw new Exception('Invalid content_type value provided: ' . $this->config['content_type']);
|
174 |
+
}
|
175 |
+
}
|
176 |
+
}
|
177 |
|
178 |
+
protected function validateParameters($params) {
|
179 |
+
if (!is_array($params)) {
|
180 |
+
throw new Exception(
|
181 |
+
'BV class constructor argument $params must be an array.'
|
182 |
+
);
|
183 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
|
185 |
+
// check to make sure we have the required parameters.
|
186 |
+
if (empty($params['bv_root_folder'])) {
|
187 |
+
throw new Exception(
|
188 |
+
'BV class constructor argument $params is missing required bv_root_folder key. An ' .
|
189 |
+
'array containing bv_root_folder (string) is expected.'
|
190 |
);
|
191 |
+
}
|
192 |
|
193 |
+
if (empty($params['subject_id'])) {
|
194 |
+
throw new Exception(
|
195 |
+
'BV class constructor argument $params is missing required subject_id key. An ' .
|
196 |
+
'array containing subject_id (string) is expected.'
|
197 |
+
);
|
198 |
+
}
|
199 |
+
}
|
200 |
+
}
|
201 |
+
// end of BV class
|
202 |
|
203 |
+
/**
|
204 |
+
* Base Class containing most shared functionality. So when we add support for
|
205 |
+
* questions and answers it should be minimal changes. Just need to create an
|
206 |
+
* answers class which inherits from Base.
|
207 |
+
*
|
208 |
+
* Configuration array is required for creation class object.
|
209 |
+
*
|
210 |
+
*/
|
211 |
+
class Base {
|
212 |
+
private $msg = '';
|
213 |
|
214 |
+
public function __construct($params = array()) {
|
|
|
|
|
|
|
215 |
|
216 |
+
$this->validateParams($params);
|
217 |
|
218 |
+
$this->config = $params;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
|
220 |
+
// setup bv (internal) defaults
|
221 |
+
$this->bv_config['seo-domain']['staging'] = 'seo-stg.bazaarvoice.com';
|
222 |
+
$this->bv_config['seo-domain']['production'] = 'seo.bazaarvoice.com';
|
223 |
+
$this->bv_config['seo-domain']['testing_staging'] = 'seo-qa-stg.bazaarvoice.com';
|
224 |
+
$this->bv_config['seo-domain']['testing_production'] = 'seo-qa.bazaarvoice.com';
|
225 |
|
226 |
+
// seller rating display is a special snowflake
|
227 |
+
$this->bv_config['srd-domain'] = 'srd.bazaarvoice.com';
|
228 |
+
$this->bv_config['srd-prefix-staging'] = 'stg';
|
229 |
+
$this->bv_config['srd-prefix-production'] = 'prod';
|
230 |
+
$this->bv_config['srd-prefix-testing_staging'] = 'qa-stg';
|
231 |
+
$this->bv_config['srd-prefix-testing_production'] = 'qa';
|
232 |
+
|
233 |
+
$this->config['latency_timeout'] = $this->_isBot()
|
234 |
+
? $this->config['execution_timeout_bot']
|
235 |
+
: $this->config['execution_timeout'];
|
236 |
+
}
|
237 |
|
238 |
+
protected function validateParams($params) {
|
239 |
+
if (!is_array($params)) {
|
240 |
+
throw new Exception('BV Base Class missing config array.');
|
241 |
+
}
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* A check on the bvstate parameter content type value.
|
246 |
+
*/
|
247 |
+
protected function _checkBVStateContentType() {
|
248 |
+
if (empty($this->config['page_params']['content_type'])) {
|
249 |
+
return TRUE;
|
250 |
}
|
|
|
251 |
|
252 |
+
if (
|
253 |
+
!empty($this->config['page_params']['content_type']) &&
|
254 |
+
$this->config['page_params']['content_type'] == $this->config['content_type']
|
255 |
+
) {
|
256 |
+
return TRUE;
|
257 |
+
}
|
258 |
|
259 |
+
return FALSE;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Function for collecting messages.
|
264 |
+
*/
|
265 |
+
protected function _setBuildMessage($msg) {
|
266 |
+
$msg = rtrim($msg, ";");
|
267 |
+
$this->msg .= ' ' . $msg . ';';
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Is this SDK enabled?
|
272 |
+
*
|
273 |
+
* Return true if either seo_sdk_enabled is set truthy or bvreveal flags are
|
274 |
+
* set.
|
275 |
+
*/
|
276 |
+
private function _isSdkEnabled() {
|
277 |
+
return $this->config['seo_sdk_enabled'] || $this->_getBVReveal();
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Check if charset is correct, if not set to default
|
282 |
+
*/
|
283 |
+
private function _checkCharset($seo_content) {
|
284 |
+
if (isset($this->config['charset'])) {
|
285 |
+
$supportedCharsets = mb_list_encodings();
|
286 |
+
if (!in_array($this->config['charset'], $supportedCharsets)) {
|
287 |
+
$this->config['charset'] = DEFAULT_CHARSET;
|
288 |
+
$this->_setBuildMessage("Charset is not configured properly. "
|
289 |
+
. "BV-SEO-SDK will load default charset and continue.");
|
290 |
+
}
|
291 |
+
} else {
|
292 |
+
$this->config['charset'] = DEFAULT_CHARSET;
|
293 |
+
}
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Return encoded content with set charset
|
298 |
+
*/
|
299 |
+
private function _charsetEncode($seo_content) {
|
300 |
+
if (isset($this->config['charset'])) {
|
301 |
+
$enc = mb_detect_encoding($seo_content);
|
302 |
+
$seo_content = mb_convert_encoding($seo_content, $this->config['charset'], $enc);
|
303 |
+
}
|
304 |
|
305 |
+
return $seo_content;
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Return full SEO content.
|
310 |
+
*/
|
311 |
+
private function _getFullSeoContents() {
|
312 |
+
$seo_content = '';
|
313 |
+
|
314 |
+
// get the page number of SEO content to load
|
315 |
+
$page_number = $this->_getPageNumber();
|
316 |
+
|
317 |
+
// build the URL to access the SEO content for
|
318 |
+
// this product / page combination
|
319 |
+
$this->seo_url = $this->_buildSeoUrl($page_number);
|
320 |
+
|
321 |
+
// make call to get SEO payload from cloud unless seo_sdk_enabled is false
|
322 |
+
// make call if bvreveal param in query string is set to 'debug'
|
323 |
+
if ($this->_isSdkEnabled()) {
|
324 |
+
$seo_content = $this->_fetchSeoContent($this->seo_url);
|
325 |
+
|
326 |
+
$this->_checkCharset($seo_content);
|
327 |
+
$seo_content = $this->_charsetEncode($seo_content);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
|
329 |
+
// replace tokens for pagination URLs with page_url
|
330 |
+
$seo_content = $this->_replaceTokens($seo_content);
|
331 |
+
}
|
332 |
+
// show footer even if seo_sdk_enabled flag is false
|
333 |
+
else {
|
334 |
+
$this->_setBuildMessage(
|
335 |
+
'SEO SDK is disabled. Enable by setting seo.sdk.enabled to true.'
|
336 |
+
);
|
337 |
}
|
338 |
|
339 |
+
$payload = $seo_content;
|
340 |
|
341 |
+
return $payload;
|
342 |
+
}
|
|
|
343 |
|
344 |
+
/**
|
345 |
+
* Remove predefined section from a string.
|
346 |
+
*/
|
347 |
+
private function _replaceSection($str, $search_str_begin, $search_str_end) {
|
348 |
+
$result = $str;
|
349 |
+
$start_index = mb_strrpos($str, $search_str_begin);
|
|
|
|
|
|
|
350 |
|
351 |
+
if ($start_index !== false) {
|
352 |
+
$end_index = mb_strrpos($str, $search_str_end);
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
|
354 |
+
if ($end_index !== false) {
|
355 |
+
$end_index += mb_strlen($search_str_end);
|
356 |
+
$str_begin = mb_substr($str, 0, $start_index);
|
357 |
+
$str_end = mb_substr($str, $end_index);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|