update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit 47263617c5
60 changed files with 418860 additions and 226988 deletions

View file

@ -1,27 +1,31 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SEO;
use Piwik\DataTable;
use Piwik\Piwik;
use Piwik\Plugins\SEO\Metric\Aggregator;
use Piwik\Plugins\SEO\Metric\Metric;
use Piwik\Plugins\SEO\Metric\ProviderCache;
use Piwik\Url;
/**
* @see plugins/Referrers/functions.php
* @method static \Piwik\Plugins\SEO\API getInstance()
* @method static API getInstance()
*/
require_once PIWIK_INCLUDE_PATH . '/plugins/Referrers/functions.php';
/**
* The SEO API lets you access a list of SEO metrics for the specified URL: Google Pagerank, Goolge/Bing indexed pages
* The SEO API lets you access a list of SEO metrics for the specified URL: Google PageRank, Google/Bing indexed pages
* Alexa Rank, age of the Domain name and count of DMOZ entries.
*
* @method static \Piwik\Plugins\SEO\API getInstance()
* @method static API getInstance()
*/
class API extends \Piwik\Plugin\API
{
@ -34,62 +38,38 @@ class API extends \Piwik\Plugin\API
public function getRank($url)
{
Piwik::checkUserHasSomeViewAccess();
$rank = new RankChecker($url);
$linkToMajestic = MajesticClient::getLinkForUrl($url);
$metricProvider = new ProviderCache(new Aggregator());
$domain = Url::getHostFromUrl($url);
$metrics = $metricProvider->getMetrics($domain);
$data = array(
'Google PageRank' => array(
'rank' => $rank->getPageRank(),
'logo' => \Piwik\Plugins\Referrers\getSearchEngineLogoFromUrl('http://google.com'),
'id' => 'pagerank'
),
Piwik::translate('SEO_Google_IndexedPages') => array(
'rank' => $rank->getIndexedPagesGoogle(),
'logo' => \Piwik\Plugins\Referrers\getSearchEngineLogoFromUrl('http://google.com'),
'id' => 'google-index',
),
Piwik::translate('SEO_Bing_IndexedPages') => array(
'rank' => $rank->getIndexedPagesBing(),
'logo' => \Piwik\Plugins\Referrers\getSearchEngineLogoFromUrl('http://bing.com'),
'id' => 'bing-index',
),
Piwik::translate('SEO_AlexaRank') => array(
'rank' => $rank->getAlexaRank(),
'logo' => \Piwik\Plugins\Referrers\getSearchEngineLogoFromUrl('http://alexa.com'),
'id' => 'alexa',
),
Piwik::translate('SEO_DomainAge') => array(
'rank' => $rank->getAge(),
'logo' => 'plugins/SEO/images/whois.png',
'id' => 'domain-age',
),
Piwik::translate('SEO_ExternalBacklinks') => array(
'rank' => $rank->getExternalBacklinkCount(),
'logo' => 'plugins/SEO/images/majesticseo.png',
'logo_link' => $linkToMajestic,
'logo_tooltip' => Piwik::translate('SEO_ViewBacklinksOnMajesticSEO'),
'id' => 'external-backlinks',
),
Piwik::translate('SEO_ReferrerDomains') => array(
'rank' => $rank->getReferrerDomainCount(),
'logo' => 'plugins/SEO/images/majesticseo.png',
'logo_link' => $linkToMajestic,
'logo_tooltip' => Piwik::translate('SEO_ViewBacklinksOnMajesticSEO'),
'id' => 'referrer-domains',
),
);
return $this->toDataTable($metrics);
}
// Add DMOZ only if > 0 entries found
$dmozRank = array(
'rank' => $rank->getDmoz(),
'logo' => \Piwik\Plugins\Referrers\getSearchEngineLogoFromUrl('http://dmoz.org'),
'id' => 'dmoz',
);
if ($dmozRank['rank'] > 0) {
$data[Piwik::translate('SEO_Dmoz')] = $dmozRank;
/**
* @param Metric[] $metrics
* @return DataTable
*/
private function toDataTable(array $metrics)
{
$translated = array();
foreach ($metrics as $metric) {
if (!$metric instanceof Metric) {
continue;
}
$label = Piwik::translate($metric->getName());
$translated[$label] = array(
'id' => $metric->getId(),
'rank' => $metric->getValue(),
'logo' => $metric->getLogo(),
'logo_link' => $metric->getLogoLink(),
'logo_tooltip' => Piwik::translate($metric->getLogoTooltip()),
'rank_suffix' => Piwik::translate($metric->getValueSuffix()),
);
}
return DataTable::makeFromIndexedArray($data);
return DataTable::makeFromIndexedArray($translated);
}
}

View file

@ -1,97 +0,0 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SEO;
use Piwik\Common;
use Piwik\Http;
/**
* Client for Majestic SEO's HTTP API.
*
* Hides the HTTP request sending logic.
*/
class MajesticClient
{
const API_BASE = 'http://simpleapi.majesticseo.com/sapi/';
const API_KEY = 'ETHPYY'; // please only use this key within Piwik
/**
* Returns a URL that can be used to view all SEO data for a particular website.
*
* @param string $targetSiteUrl The URL of the website for whom SEO stats should be
* accessible for.
* @return string
*/
public static function getLinkForUrl($targetSiteUrl)
{
$domain = @parse_url($targetSiteUrl, PHP_URL_HOST);
return "http://www.majesticseo.com/reports/site-explorer/summary/$domain?IndexDataSource=F";
}
/**
* Returns backlink statistics including the count of backlinks and count of
* referrer domains (domains with backlinks).
*
* This method issues an HTTP request and waits for it to return.
*
* @param string $siteDomain The domain of the website to get stats for.
* @param int $timeout The number of seconds to wait before aborting
* the HTTP request.
* @return array An array containing the backlink count and referrer
* domain count:
* array(
* 'backlink_count' => X,
* 'referrer_domains_count' => Y
* )
* If either stat is false, either the API returned an
* error, or the IP was blocked for this request.
*/
public function getBacklinkStats($siteDomain, $timeout = 300)
{
$apiUrl = $this->getApiUrl($method = 'GetBacklinkStats', $args = array(
'items' => '1',
'item0' => $siteDomain
));
$apiResponse = Http::sendHttpRequest($apiUrl, $timeout);
$result = array(
'backlink_count' => false,
'referrer_domains_count' => false
);
$apiResponse = Common::json_decode($apiResponse, $assoc = true);
if (!empty($apiResponse)
&& !empty($apiResponse['Data'])
) {
$siteSeoStats = reset($apiResponse['Data']);
if (isset($siteSeoStats['ExtBackLinks'])
&& $siteSeoStats['ExtBackLinks'] !== -1
) {
$result['backlink_count'] = $siteSeoStats['ExtBackLinks'];
}
if (isset($siteSeoStats['RefDomains'])
&& $siteSeoStats['RefDomains'] !== -1
) {
$result['referrer_domains_count'] = $siteSeoStats['RefDomains'];
}
}
return $result;
}
private function getApiUrl($method, $args = array())
{
$args['sak'] = self::API_KEY;
$queryString = http_build_query($args);
return self::API_BASE . $method . '?' . $queryString;
}
}

View file

@ -0,0 +1,65 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Container\StaticContainer;
use Piwik\Metrics\Formatter;
use Piwik\Piwik;
/**
* Aggregates metrics from several providers.
*/
class Aggregator implements MetricsProvider
{
/**
* @var MetricsProvider[]
*/
private $providers;
public function __construct()
{
$this->providers = $this->getProviders();
}
public function getMetrics($domain)
{
$metrics = array();
foreach ($this->providers as $provider) {
$metrics = array_merge($metrics, $provider->getMetrics($domain));
}
return $metrics;
}
/**
* @return MetricsProvider[]
*/
private function getProviders()
{
$container = StaticContainer::getContainer();
$providers = array(
$container->get('Piwik\Plugins\SEO\Metric\Google'),
$container->get('Piwik\Plugins\SEO\Metric\Bing'),
$container->get('Piwik\Plugins\SEO\Metric\Alexa'),
$container->get('Piwik\Plugins\SEO\Metric\DomainAge'),
$container->get('Piwik\Plugins\SEO\Metric\Dmoz'),
);
/**
* Use this event to register new SEO metrics providers.
*
* @param array $providers Contains an array of Piwik\Plugins\SEO\Metric\MetricsProvider instances.
*/
Piwik::postEvent('SEO.getMetricsProviders', array(&$providers));
return $providers;
}
}

View file

@ -0,0 +1,53 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Http;
use Piwik\NumberFormatter;
use Piwik\Plugins\Referrers\SearchEngine;
use Psr\Log\LoggerInterface;
/**
* Retrieves the Alexa rank.
*/
class Alexa implements MetricsProvider
{
const URL = 'http://data.alexa.com/data?cli=10&url=';
const LINK = 'http://www.alexa.com/siteinfo/';
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function getMetrics($domain)
{
try {
$response = Http::sendHttpRequest(self::URL . urlencode($domain), $timeout = 10, @$_SERVER['HTTP_USER_AGENT']);
$xml = @simplexml_load_string($response);
$value = $xml ? NumberFormatter::getInstance()->formatNumber((int)$xml->SD->POPULARITY['TEXT']) : null;
} catch (\Exception $e) {
$this->logger->warning('Error while getting Alexa SEO stats: {message}', array('message' => $e->getMessage()));
$value = null;
}
$logo = SearchEngine::getInstance()->getLogoFromUrl('http://alexa.com');
$link = self::LINK . urlencode($domain);
return array(
new Metric('alexa', 'SEO_AlexaRank', $value, $logo, $link)
);
}
}

View file

@ -0,0 +1,56 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Http;
use Piwik\NumberFormatter;
use Piwik\Plugins\Referrers\SearchEngine;
use Psr\Log\LoggerInterface;
/**
* Fetches the number of pages indexed in Bing.
*/
class Bing implements MetricsProvider
{
const URL = 'http://www.bing.com/search?mkt=en-US&q=site%3A';
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function getMetrics($domain)
{
$url = self::URL . urlencode($domain);
try {
$response = str_replace('&nbsp;', ' ', Http::sendHttpRequest($url, $timeout = 10, @$_SERVER['HTTP_USER_AGENT']));
if (preg_match('#([0-9\,]+) results#i', $response, $p)) {
$pageCount = NumberFormatter::getInstance()->formatNumber((int)str_replace(',', '', $p[1]));
} else {
$pageCount = 0;
}
} catch (\Exception $e) {
$this->logger->warning('Error while getting Bing SEO stats: {message}', array('message' => $e->getMessage()));
$pageCount = null;
}
$logo = SearchEngine::getInstance()->getLogoFromUrl('http://bing.com');
return array(
new Metric('bing-index', 'SEO_Bing_IndexedPages', $pageCount, $logo, null, null, 'General_Pages')
);
}
}

View file

@ -0,0 +1,63 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Http;
use Piwik\NumberFormatter;
use Piwik\Plugins\Referrers\SearchEngine;
use Psr\Log\LoggerInterface;
/**
* Retrieves the number of Dmoz.org entries.
*/
class Dmoz implements MetricsProvider
{
const URL = 'http://www.dmoz.org/search?q=';
/**
* @var LoggerInterface
*/
private $logger;
/**
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function getMetrics($domain)
{
try {
$response = Http::sendHttpRequest(self::URL . urlencode($domain), $timeout = 10, @$_SERVER['HTTP_USER_AGENT']);
preg_match('#DMOZ Sites[^\(]+\([0-9]-[0-9]+ of ([0-9]+)\)#', $response, $p);
if (!empty($p[1])) {
$value = NumberFormatter::getInstance()->formatNumber((int)$p[1]);
} else {
$value = 0;
}
// Add DMOZ only if > 0 entries found
if ($value == 0) {
return array();
}
} catch (\Exception $e) {
$this->logger->warning('Error while getting Dmoz SEO stats: {message}', array('message' => $e->getMessage()));
$value = null;
}
$logo = SearchEngine::getInstance()->getLogoFromUrl('http://dmoz.org');
return array(
new Metric('dmoz', 'SEO_Dmoz', $value, $logo)
);
}
}

View file

@ -0,0 +1,141 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Http;
use Piwik\Metrics\Formatter;
use Psr\Log\LoggerInterface;
/**
* Fetches the domain age using archive.org, who.is and whois.com.
*/
class DomainAge implements MetricsProvider
{
/**
* @var Formatter
*/
private $formatter;
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(Formatter $formatter, LoggerInterface $logger)
{
$this->formatter = $formatter;
$this->logger = $logger;
}
public function getMetrics($domain)
{
$ages = array();
$age = $this->getAgeArchiveOrg($domain);
if ($age > 0) {
$ages[] = $age;
}
$age = $this->getAgeWhoIs($domain);
if ($age > 0) {
$ages[] = $age;
}
$age = $this->getAgeWhoisCom($domain);
if ($age > 0) {
$ages[] = $age;
}
if (count($ages) > 0) {
$value = min($ages);
$value = $this->formatter->getPrettyTimeFromSeconds(time() - $value, true);
} else {
$value = null;
}
return array(
new Metric('domain-age', 'SEO_DomainAge', $value, 'plugins/SEO/images/whois.png')
);
}
/**
* Returns the domain age archive.org lists for the current url
*
* @param string $domain
* @return int
*/
private function getAgeArchiveOrg($domain)
{
$url = str_replace('www.', '', $domain);
$data = $this->getUrl('http://wayback.archive.org/web/*/' . urlencode($url));
preg_match('#<a href=\"([^>]*)' . preg_quote($url) . '/\">([^<]*)<\/a>#', $data, $p);
if (!empty($p[2])) {
$value = strtotime($p[2]);
if ($value === false) {
return 0;
}
return $value;
}
return 0;
}
/**
* Returns the domain age who.is lists for the current url
*
* @param string $domain
* @return int
*/
private function getAgeWhoIs($domain)
{
$url = preg_replace('/^www\./', '', $domain);
$url = 'http://www.who.is/whois/' . urlencode($url);
$data = $this->getUrl($url);
preg_match('#(?:Creation Date|Created On|created|Registered on)\.*:\s*([ \ta-z0-9\/\-:\.]+)#si', $data, $p);
if (!empty($p[1])) {
$value = strtotime(trim($p[1]));
if ($value === false) {
return 0;
}
return $value;
}
return 0;
}
/**
* Returns the domain age whois.com lists for the current url
*
* @param string $domain
* @return int
*/
private function getAgeWhoisCom($domain)
{
$url = preg_replace('/^www\./', '', $domain);
$url = 'http://www.whois.com/whois/' . urlencode($url);
$data = $this->getUrl($url);
preg_match('#(?:Creation Date|Created On|created):\s*([ \ta-z0-9\/\-:\.]+)#si', $data, $p);
if (!empty($p[1])) {
$value = strtotime(trim($p[1]));
if ($value === false) {
return 0;
}
return $value;
}
return 0;
}
private function getUrl($url)
{
try {
return str_replace('&nbsp;', ' ', Http::sendHttpRequest($url, $timeout = 10, @$_SERVER['HTTP_USER_AGENT']));
} catch (\Exception $e) {
$this->logger->warning('Error while getting SEO stats (domain age): {message}', array('message' => $e->getMessage()));
return '';
}
}
}

View file

@ -0,0 +1,172 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Http;
use Piwik\NumberFormatter;
use Piwik\Plugins\Referrers\SearchEngine;
use Psr\Log\LoggerInterface;
/**
* Retrieves Google PageRank.
*/
class Google implements MetricsProvider
{
const SEARCH_URL = 'http://www.google.com/search?hl=en&q=site%3A';
/**
* @var LoggerInterface
*/
private $logger;
/**
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function getMetrics($domain)
{
$pageCount = $this->fetchIndexedPagesCount($domain);
$pageRank = $this->fetchPageRank($domain);
$logo = SearchEngine::getInstance()->getLogoFromUrl('http://google.com');
return array(
new Metric('google-index', 'SEO_Google_IndexedPages', $pageCount, $logo, null, null, 'General_Pages'),
new Metric('pagerank', 'Google PageRank', $pageRank, $logo, null, null, '/10'),
);
}
public function fetchIndexedPagesCount($domain)
{
$url = self::SEARCH_URL . urlencode($domain);
try {
$response = str_replace('&nbsp;', ' ', Http::sendHttpRequest($url, $timeout = 10, @$_SERVER['HTTP_USER_AGENT']));
if (preg_match('#([0-9\,]+) results#i', $response, $p)) {
return NumberFormatter::getInstance()->formatNumber((int)str_replace(',', '', $p[1]));
} else {
return 0;
}
} catch (\Exception $e) {
$this->logger->warning('Error while getting Google search SEO stats: {message}', array('message' => $e->getMessage()));
return null;
}
}
public function fetchPageRank($domain)
{
$chwrite = $this->checkHash($this->hashURL($domain));
$url = "http://toolbarqueries.google.com/tbr?client=navclient-auto&ch=" . $chwrite . "&features=Rank&q=info:" . $domain . "&num=100&filter=0";
try {
$response = Http::sendHttpRequest($url, $timeout = 10, @$_SERVER['HTTP_USER_AGENT']);
preg_match('#Rank_[0-9]:[0-9]:([0-9]+){1,}#si', $response, $p);
return isset($p[1]) ? $p[1] : null;
} catch (\Exception $e) {
$this->logger->warning('Error while getting Google PageRank for SEO stats: {message}', array('message' => $e->getMessage()));
return null;
}
}
/**
* Generate a hash for a url
*
* @param string $string
* @return int
*/
private function hashURL($string)
{
$Check1 = $this->strToNum($string, 0x1505, 0x21);
$Check2 = $this->strToNum($string, 0, 0x1003F);
$Check1 >>= 2;
$Check1 = (($Check1 >> 4) & 0x3FFFFC0) | ($Check1 & 0x3F);
$Check1 = (($Check1 >> 4) & 0x3FFC00) | ($Check1 & 0x3FF);
$Check1 = (($Check1 >> 4) & 0x3C000) | ($Check1 & 0x3FFF);
$T1 = (((($Check1 & 0x3C0) << 4) | ($Check1 & 0x3C)) << 2) | ($Check2 & 0xF0F);
$T2 = (((($Check1 & 0xFFFFC000) << 4) | ($Check1 & 0x3C00)) << 0xA) | ($Check2 & 0xF0F0000);
return ($T1 | $T2);
}
/**
* Generate a checksum for the hash string
*
* @param int $hashnum
* @return string
*/
private function checkHash($hashnum)
{
$CheckByte = 0;
$Flag = 0;
$HashStr = sprintf('%u', $hashnum);
$length = strlen($HashStr);
for ($i = $length - 1; $i >= 0; $i--) {
$Re = $HashStr{$i};
if (1 === ($Flag % 2)) {
$Re += $Re;
$Re = (int)($Re / 10) + ($Re % 10);
}
$CheckByte += $Re;
$Flag++;
}
$CheckByte %= 10;
if (0 !== $CheckByte) {
$CheckByte = 10 - $CheckByte;
if (1 === ($Flag % 2)) {
if (1 === ($CheckByte % 2)) {
$CheckByte += 9;
}
$CheckByte >>= 1;
}
}
return '7' . $CheckByte . $HashStr;
}
/**
* Convert numeric string to int
*
* @param string $Str
* @param int $Check
* @param int $Magic
* @return int
*/
private function strToNum($Str, $Check, $Magic)
{
$Int32Unit = 4294967296; // 2^32
$length = strlen($Str);
for ($i = 0; $i < $length; $i++) {
$Check *= $Magic;
// If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31),
// the result of converting to integer is undefined
// refer to http://www.php.net/manual/en/language.types.integer.php
if ($Check >= $Int32Unit) {
$Check = ($Check - $Int32Unit * (int)($Check / $Int32Unit));
//if the check less than -2^31
$Check = ($Check < -2147483648) ? ($Check + $Int32Unit) : $Check;
}
$Check += ord($Str{$i});
}
return $Check;
}
}

View file

@ -0,0 +1,145 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
/**
* Describes a SEO metric.
*/
class Metric
{
/**
* @var string
*/
private $id;
/**
* @var string
*/
private $name;
/**
* @var string
*/
private $value;
/**
* @var string
*/
private $logo;
/**
* @var string|null
*/
private $logoLink;
/**
* @var string|null
*/
private $logoTooltip;
/**
* @var string|null
*/
private $valueSuffix;
/**
* @param string $id
* @param string $name Can be a string or a translation ID.
* @param string $value Rank value.
* @param string $logo URL to a logo.
* @param string|null $logoLink
* @param string|null $logoTooltip
* @param string|null $valueSuffix
*/
public function __construct($id, $name, $value, $logo, $logoLink = null, $logoTooltip = null, $valueSuffix = null)
{
$this->id = $id;
$this->name = $name;
$this->value = $value;
$this->logo = $logo;
$this->logoLink = $logoLink;
$this->logoTooltip = $logoTooltip;
$this->valueSuffix = $valueSuffix;
}
/**
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* @return string
*/
public function getLogo()
{
return $this->logo;
}
/**
* @return string|null
*/
public function getLogoLink()
{
return $this->logoLink;
}
/**
* @return string|null
*/
public function getLogoTooltip()
{
return $this->logoTooltip;
}
/**
* @return null|string
*/
public function getValueSuffix()
{
return $this->valueSuffix;
}
/**
* Allows the class to be serialized with var_export (in the cache).
*
* @param array $array
* @return Metric
*/
public static function __set_state($array)
{
return new self(
$array['id'],
$array['name'],
$array['value'],
$array['logo'],
$array['logoLink'],
$array['logoTooltip'],
$array['valueSuffix']
);
}
}

View file

@ -0,0 +1,21 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
/**
* Provides SEO metrics for a domain.
*/
interface MetricsProvider
{
/**
* @param string $domain
* @return Metric[]
*/
public function getMetrics($domain);
}

View file

@ -0,0 +1,48 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\SEO\Metric;
use Piwik\Cache;
/**
* Caches another provider.
*/
class ProviderCache implements MetricsProvider
{
/**
* @var MetricsProvider
*/
private $provider;
/**
* @var Cache\Lazy
*/
private $cache;
public function __construct(MetricsProvider $provider)
{
$this->provider = $provider;
$this->cache = Cache::getLazyCache();
}
public function getMetrics($domain)
{
$cacheId = 'SEO_getRank_' . md5($domain);
$metrics = $this->cache->fetch($cacheId);
if (! is_array($metrics)) {
$metrics = $this->provider->getMetrics($domain);
$this->cache->save($cacheId, $metrics, 60 * 60 * 6);
}
return $metrics;
}
}

View file

@ -1,377 +0,0 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SEO;
use Exception;
use Piwik\Http;
use Piwik\Log;
use Piwik\MetricsFormatter;
/**
* The functions below are derived/adapted from GetRank.org's
* Free PageRank Script v2.0, released under GPL.
*
* @copyright Copyright (C) 2007 - 2010 GetRank.Org All rights reserved.
* @link http://www.getrank.org/free-pagerank-script/
* @license GPL
*/
class RankChecker
{
private $url;
private $majesticInfo = null;
public function __construct($url)
{
$this->url = self::extractDomainFromUrl($url);
}
/**
* Extract domain from URL as the web services generally
* expect only a domain name (i.e., no protocol, port, path, query, etc).
*
* @param string $url
* @return string
*/
static public function extractDomainFromUrl($url)
{
return preg_replace(
array(
'~^https?\://~si', // strip protocol
'~[/:#?;%&].*~', // strip port, path, query, anchor, etc
'~\.$~', // trailing period
),
'', $url);
}
/**
* Web service proxy that retrieves the content at the specified URL
*
* @param string $url
* @return string
*/
private function getPage($url)
{
try {
return str_replace('&nbsp;', ' ', Http::sendHttpRequest($url, $timeout = 10, @$_SERVER['HTTP_USER_AGENT']));
} catch (Exception $e) {
return '';
}
}
/**
* Returns the google page rank for the current url
*
* @return int
*/
public function getPageRank()
{
$chwrite = $this->CheckHash($this->HashURL($this->url));
$url = "http://toolbarqueries.google.com/tbr?client=navclient-auto&ch=" . $chwrite . "&features=Rank&q=info:" . $this->url . "&num=100&filter=0";
$data = $this->getPage($url);
preg_match('#Rank_[0-9]:[0-9]:([0-9]+){1,}#si', $data, $p);
$value = isset($p[1]) ? $p[1] : 0;
return $value;
}
/**
* Returns the alexa traffic rank for the current url
*
* @return int
*/
public function getAlexaRank()
{
$xml = @simplexml_load_string($this->getPage('http://data.alexa.com/data?cli=10&url=' . urlencode($this->url)));
return $xml ? $xml->SD->POPULARITY['TEXT'] : '';
}
/**
* Returns the number of Dmoz.org entries for the current url
*
* @return int
*/
public function getDmoz()
{
$url = 'http://www.dmoz.org/search?q=' . urlencode($this->url);
$data = $this->getPage($url);
preg_match('#Open Directory Sites[^\(]+\([0-9]-[0-9]+ of ([0-9]+)\)#', $data, $p);
if (!empty($p[1])) {
return (int)$p[1];
}
return 0;
}
/**
* Returns the number of pages google holds in it's index for the current url
*
* @return int
*/
public function getIndexedPagesGoogle()
{
$url = 'http://www.google.com/search?hl=en&q=site%3A' . urlencode($this->url);
$data = $this->getPage($url);
if (preg_match('#([0-9\,]+) results#i', $data, $p)) {
$indexedPages = (int)str_replace(',', '', $p[1]);
return $indexedPages;
}
return 0;
}
/**
* Returns the number of pages bing holds in it's index for the current url
*
* @return int
*/
public function getIndexedPagesBing()
{
$url = 'http://www.bing.com/search?mkt=en-US&q=site%3A' . urlencode($this->url);
$data = $this->getPage($url);
if (preg_match('#([0-9\,]+) results#i', $data, $p)) {
return (int)str_replace(',', '', $p[1]);
}
return 0;
}
/**
* Returns the domain age for the current url
*
* @return int
*/
public function getAge()
{
$ageArchiveOrg = $this->_getAgeArchiveOrg();
$ageWhoIs = $this->_getAgeWhoIs();
$ageWhoisCom = $this->_getAgeWhoisCom();
$ages = array();
if ($ageArchiveOrg > 0) {
$ages[] = $ageArchiveOrg;
}
if ($ageWhoIs > 0) {
$ages[] = $ageWhoIs;
}
if ($ageWhoisCom > 0) {
$ages[] = $ageWhoisCom;
}
if (count($ages) > 1) {
$maxAge = min($ages);
} else {
$maxAge = array_shift($ages);
}
if ($maxAge) {
return MetricsFormatter::getPrettyTimeFromSeconds(time() - $maxAge);
}
return false;
}
/**
* Returns the number backlinks that link to the current site.
*
* @return int
*/
public function getExternalBacklinkCount()
{
try {
$majesticInfo = $this->getMajesticInfo();
return $majesticInfo['backlink_count'];
} catch (Exception $e) {
Log::info($e);
return 0;
}
}
/**
* Returns the number of referrer domains that link to the current site.
*
* @return int
*/
public function getReferrerDomainCount()
{
try {
$majesticInfo = $this->getMajesticInfo();
return $majesticInfo['referrer_domains_count'];
} catch (Exception $e) {
Log::info($e);
return 0;
}
}
/**
* Returns the domain age archive.org lists for the current url
*
* @return int
*/
protected function _getAgeArchiveOrg()
{
$url = str_replace('www.', '', $this->url);
$data = @$this->getPage('http://wayback.archive.org/web/*/' . urlencode($url));
preg_match('#<a href=\"([^>]*)' . preg_quote($url) . '/\">([^<]*)<\/a>#', $data, $p);
if (!empty($p[2])) {
$value = strtotime($p[2]);
if ($value === false) {
return 0;
}
return $value;
}
return 0;
}
/**
* Returns the domain age who.is lists for the current url
*
* @return int
*/
protected function _getAgeWhoIs()
{
$url = preg_replace('/^www\./', '', $this->url);
$url = 'http://www.who.is/whois/' . urlencode($url);
$data = $this->getPage($url);
preg_match('#(?:Creation Date|Created On|Registered on)\.*:\s*([ \ta-z0-9\/\-:\.]+)#si', $data, $p);
if (!empty($p[1])) {
$value = strtotime(trim($p[1]));
if ($value === false) {
return 0;
}
return $value;
}
return 0;
}
/**
* Returns the domain age whois.com lists for the current url
*
* @return int
*/
protected function _getAgeWhoisCom()
{
$url = preg_replace('/^www\./', '', $this->url);
$url = 'http://www.whois.com/whois/' . urlencode($url);
$data = $this->getPage($url);
preg_match('#(?:Creation Date|Created On):\s*([ \ta-z0-9\/\-:\.]+)#si', $data, $p);
if (!empty($p[1])) {
$value = strtotime(trim($p[1]));
if ($value === false) {
return 0;
}
return $value;
}
return 0;
}
/**
* Convert numeric string to int
*
* @see getPageRank()
*
* @param string $Str
* @param int $Check
* @param int $Magic
* @return int
*/
private function StrToNum($Str, $Check, $Magic)
{
$Int32Unit = 4294967296; // 2^32
$length = strlen($Str);
for ($i = 0; $i < $length; $i++) {
$Check *= $Magic;
// If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31),
// the result of converting to integer is undefined
// refer to http://www.php.net/manual/en/language.types.integer.php
if ($Check >= $Int32Unit) {
$Check = ($Check - $Int32Unit * (int)($Check / $Int32Unit));
//if the check less than -2^31
$Check = ($Check < -2147483648) ? ($Check + $Int32Unit) : $Check;
}
$Check += ord($Str{$i});
}
return $Check;
}
/**
* Generate a hash for a url
*
* @see getPageRank()
*
* @param string $String
* @return int
*/
private function HashURL($String)
{
$Check1 = $this->StrToNum($String, 0x1505, 0x21);
$Check2 = $this->StrToNum($String, 0, 0x1003F);
$Check1 >>= 2;
$Check1 = (($Check1 >> 4) & 0x3FFFFC0) | ($Check1 & 0x3F);
$Check1 = (($Check1 >> 4) & 0x3FFC00) | ($Check1 & 0x3FF);
$Check1 = (($Check1 >> 4) & 0x3C000) | ($Check1 & 0x3FFF);
$T1 = (((($Check1 & 0x3C0) << 4) | ($Check1 & 0x3C)) << 2) | ($Check2 & 0xF0F);
$T2 = (((($Check1 & 0xFFFFC000) << 4) | ($Check1 & 0x3C00)) << 0xA) | ($Check2 & 0xF0F0000);
return ($T1 | $T2);
}
/**
* Generate a checksum for the hash string
*
* @see getPageRank()
*
* @param int $Hashnum
* @return string
*/
private function CheckHash($Hashnum)
{
$CheckByte = 0;
$Flag = 0;
$HashStr = sprintf('%u', $Hashnum);
$length = strlen($HashStr);
for ($i = $length - 1; $i >= 0; $i--) {
$Re = $HashStr{$i};
if (1 === ($Flag % 2)) {
$Re += $Re;
$Re = (int)($Re / 10) + ($Re % 10);
}
$CheckByte += $Re;
$Flag++;
}
$CheckByte %= 10;
if (0 !== $CheckByte) {
$CheckByte = 10 - $CheckByte;
if (1 === ($Flag % 2)) {
if (1 === ($CheckByte % 2)) {
$CheckByte += 9;
}
$CheckByte >>= 1;
}
}
return '7' . $CheckByte . $HashStr;
}
private function getMajesticInfo()
{
if ($this->majesticInfo === null) {
$client = new MajesticClient();
$this->majesticInfo = $client->getBacklinkStats($this->url);
}
return $this->majesticInfo;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,38 +8,8 @@
*/
namespace Piwik\Plugins\SEO;
use Piwik\Version;
use Piwik\WidgetsList;
/**
*/
class SEO extends \Piwik\Plugin
{
/**
* @see Piwik\Plugin::getInformation
*/
public function getInformation()
{
return array(
'description' => 'This Plugin extracts and displays SEO metrics: Alexa web ranking, Google Pagerank, number of Indexed pages and backlinks of the currently selected website.',
'authors' => array(array('name' => 'Piwik', 'homepage' => 'http://piwik.org/')),
'version' => Version::VERSION,
'license' => 'GPL v3+',
'license_homepage' => 'http://www.gnu.org/licenses/gpl.html'
);
}
/**
* @see Piwik\Plugin::getListHooksRegistered
*/
public function getListHooksRegistered()
{
$hooks = array('WidgetsList.addWidgets' => 'addWidgets');
return $hooks;
}
function addWidgets()
{
WidgetsList::add('SEO', 'SEO_SeoRankings', 'SEO', 'getRank');
}
}

View file

@ -0,0 +1,55 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\SEO;
use Piwik\Common;
use Piwik\DataTable\Renderer;
use Piwik\Site;
use Piwik\Url;
use Piwik\UrlHelper;
use Piwik\View;
class Widgets extends \Piwik\Plugin\Widgets
{
protected $category = 'SEO';
public function init()
{
$this->addWidget('SEO_SeoRankings', 'getRank');
}
public function getRank()
{
$idSite = Common::getRequestVar('idSite');
$site = new Site($idSite);
$url = urldecode(Common::getRequestVar('url', '', 'string'));
if (!empty($url) && strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) {
$url = 'http://' . $url;
}
if (empty($url) || !UrlHelper::isLookLikeUrl($url)) {
$url = $site->getMainUrl();
}
$dataTable = API::getInstance()->getRank($url);
$view = new View('@SEO/getRank');
$view->urlToRank = Url::getHostFromUrl($url);
/** @var \Piwik\DataTable\Renderer\Php $renderer */
$renderer = Renderer::factory('php');
$renderer->setSerialize(false);
$view->ranks = $renderer->render($dataTable);
return $view->render();
}
}

View file

@ -1,5 +1,5 @@
/*!
* Piwik - Web Analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later

View file

@ -0,0 +1,9 @@
{
"SEO": {
"AlexaRank": "رتبة أليكسا",
"DomainAge": "عمر اسن النطاق",
"Rank": "الرتبة",
"SeoRankings": "رتب ملائمة محركات البحث",
"SEORankingsFor": "رتبة ملائمة محركات البحث في %s"
}
}

View file

@ -0,0 +1,9 @@
{
"SEO": {
"AlexaRank": "Alexa ранг",
"DomainAge": "Узрост дамена",
"Rank": "Ранг",
"SeoRankings": "SEO рэйтынгі",
"SEORankingsFor": "SEO рэйтынгі для %s"
}
}

View file

@ -0,0 +1,13 @@
{
"SEO": {
"PluginDescription": "Този плъгин извлича и показва SEO метрики: Alexa уеб ранк, Google Pagerank, брой индексирани страници и брой обратни връзки за избраната уеб страница.",
"AlexaRank": "Alexa ранг",
"Bing_IndexedPages": "Bing индексирани страници",
"Dmoz": "DMOZ записи",
"DomainAge": "Възраст на домейна",
"Google_IndexedPages": "Google индексирани страници",
"Rank": "Ранг",
"SeoRankings": "SEO ранг",
"SEORankingsFor": "SEO ранг за %s"
}
}

View file

@ -0,0 +1,12 @@
{
"SEO": {
"AlexaRank": "Ranking Alexa",
"Bing_IndexedPages": "Pàgines indexades per Bing",
"Dmoz": "Entrades DMOZ",
"DomainAge": "Edat del domini",
"Google_IndexedPages": "Pàgines indexades per Google",
"Rank": "Ranking",
"SeoRankings": "Ranking SEO",
"SEORankingsFor": "Ranking SEO per %s"
}
}

View file

@ -0,0 +1,13 @@
{
"SEO": {
"PluginDescription": "Tento plugin extrahuje a zobrazuje SEO metriky: pořadí v Alexa web, Google PageRank, počet indexovaných stránek a zpětných odkazů aktuálně vybraného webu.",
"AlexaRank": "Hodnocení Alexa",
"Bing_IndexedPages": "Stránek zaindexovaných Bingem",
"Dmoz": "Záznamů v katalogu DMOZ",
"DomainAge": "Staří domény",
"Google_IndexedPages": "Stránek zaindexovaných Googlem",
"Rank": "Hodnocení",
"SeoRankings": "Hodnocení SEO",
"SEORankingsFor": "SEO hodnocení pro %s"
}
}

Some files were not shown because too many files have changed in this diff Show more